{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NondecreasingIndentation #-}
module Agda.TypeChecking.Irrelevance where
import Control.Arrow (second)
import qualified Data.Map as Map
import Agda.Interaction.Options
import Agda.Syntax.Common
import Agda.Syntax.Internal
import Agda.TypeChecking.Monad
import Agda.TypeChecking.Pretty
import Agda.TypeChecking.Reduce
import Agda.TypeChecking.Substitute.Class
import Agda.Utils.Function
import Agda.Utils.Lens
import Agda.Utils.Monad
hideAndRelParams :: Dom a -> Dom a
hideAndRelParams = hideOrKeepInstance . mapRelevance nonStrictToIrr
workOnTypes :: (MonadTCEnv m, HasOptions m, MonadDebug m)
=> m a -> m a
workOnTypes cont = do
allowed <- optExperimentalIrrelevance <$> pragmaOptions
verboseBracket "tc.irr" 60 "workOnTypes" $ workOnTypes' allowed cont
workOnTypes' :: (MonadTCEnv m) => Bool -> m a -> m a
workOnTypes' experimental
= modifyContextInfo (mapRelevance f)
. applyQuantityToContext zeroQuantity
. typeLevelReductions
. localTC (\ e -> e { envWorkingOnTypes = True })
where
f | experimental = irrToNonStrict
| otherwise = id
applyRelevanceToContext :: (MonadTCEnv tcm, LensRelevance r) => r -> tcm a -> tcm a
applyRelevanceToContext thing =
case getRelevance thing of
Relevant -> id
rel -> applyRelevanceToContextOnly rel
. applyRelevanceToJudgementOnly rel
applyRelevanceToContextOnly :: (MonadTCEnv tcm) => Relevance -> tcm a -> tcm a
applyRelevanceToContextOnly rel = localTC
$ over eContext (map $ inverseApplyRelevance rel)
. over eLetBindings (Map.map . fmap . second $ inverseApplyRelevance rel)
applyRelevanceToJudgementOnly :: (MonadTCEnv tcm) => Relevance -> tcm a -> tcm a
applyRelevanceToJudgementOnly = localTC . over eRelevance . composeRelevance
applyRelevanceToContextFunBody :: (MonadTCM tcm, LensRelevance r) => r -> tcm a -> tcm a
applyRelevanceToContextFunBody thing cont =
case getRelevance thing of
Relevant -> cont
rel -> applyWhenM (optIrrelevantProjections <$> pragmaOptions)
(applyRelevanceToContextOnly rel) $
applyRelevanceToJudgementOnly rel cont
applyQuantityToContext :: (MonadTCEnv tcm, LensQuantity q) => q -> tcm a -> tcm a
applyQuantityToContext thing =
case getQuantity thing of
Quantity1{} -> id
q -> applyQuantityToContextOnly q
. applyQuantityToJudgementOnly q
applyQuantityToContextOnly :: (MonadTCEnv tcm) => Quantity -> tcm a -> tcm a
applyQuantityToContextOnly q = localTC
$ over eContext (map $ inverseApplyQuantity q)
. over eLetBindings (Map.map . fmap . second $ inverseApplyQuantity q)
applyQuantityToJudgementOnly :: (MonadTCEnv tcm) => Quantity -> tcm a -> tcm a
applyQuantityToJudgementOnly = localTC . over eQuantity . composeQuantity
applyCohesionToContext :: (MonadTCEnv tcm, LensCohesion m) => m -> tcm a -> tcm a
applyCohesionToContext thing =
case getCohesion thing of
m | m == mempty -> id
| otherwise -> applyCohesionToContextOnly m
applyCohesionToContextOnly :: (MonadTCEnv tcm) => Cohesion -> tcm a -> tcm a
applyCohesionToContextOnly q = localTC
$ over eContext (map $ inverseApplyCohesion q)
. over eLetBindings (Map.map . fmap . second $ inverseApplyCohesion q)
splittableCohesion :: (HasOptions m, LensCohesion a) => a -> m Bool
splittableCohesion a = do
let c = getCohesion a
pure (usableCohesion c) `and2M` (pure (c /= Flat) `or2M` do optFlatSplit <$> pragmaOptions)
applyModalityToContext :: (MonadTCEnv tcm, LensModality m) => m -> tcm a -> tcm a
applyModalityToContext thing =
case getModality thing of
m | m == mempty -> id
| otherwise -> applyModalityToContextOnly m
. applyModalityToJudgementOnly m
applyModalityToContextOnly :: (MonadTCEnv tcm) => Modality -> tcm a -> tcm a
applyModalityToContextOnly m = localTC
$ over eContext (map $ inverseApplyModality m)
. over eLetBindings (Map.map . fmap . second $ inverseApplyModality m)
applyModalityToJudgementOnly :: (MonadTCEnv tcm) => Modality -> tcm a -> tcm a
applyModalityToJudgementOnly = localTC . over eModality . composeModality
applyModalityToContextFunBody :: (MonadTCM tcm, LensModality r) => r -> tcm a -> tcm a
applyModalityToContextFunBody thing cont = do
ifM (optIrrelevantProjections <$> pragmaOptions)
(applyModalityToContext m cont)
(applyRelevanceToContextFunBody (getRelevance m)
$ applyCohesionToContext (getCohesion m)
$ applyQuantityToContext (getQuantity m) cont)
where
m = getModality thing
wakeIrrelevantVars :: (MonadTCEnv tcm) => tcm a -> tcm a
wakeIrrelevantVars
= applyRelevanceToContextOnly Irrelevant
. applyQuantityToContextOnly zeroQuantity
class UsableRelevance a where
usableRel :: Relevance -> a -> TCM Bool
instance UsableRelevance Term where
usableRel rel u = case u of
Var i vs -> do
irel <- getRelevance <$> domOfBV i
let ok = irel `moreRelevant` rel
reportSDoc "tc.irr" 50 $
"Variable" <+> prettyTCM (var i) <+>
text ("has relevance " ++ show irel ++ ", which is " ++
(if ok then "" else "NOT ") ++ "more relevant than " ++ show rel)
return ok `and2M` usableRel rel vs
Def f vs -> do
frel <- relOfConst f
return (frel `moreRelevant` rel) `and2M` usableRel rel vs
Con c _ vs -> usableRel rel vs
Lit l -> return True
Lam _ v -> usableRel rel v
Pi a b -> usableRel rel (a,b)
Sort s -> usableRel rel s
Level l -> return True
MetaV m vs -> do
mrel <- getMetaRelevance <$> lookupMeta m
return (mrel `moreRelevant` rel) `and2M` usableRel rel vs
DontCare v -> usableRel rel v
Dummy{} -> return True
instance UsableRelevance a => UsableRelevance (Type' a) where
usableRel rel (El _ t) = usableRel rel t
instance UsableRelevance Sort where
usableRel rel s = case s of
Type l -> usableRel rel l
Prop l -> usableRel rel l
Inf -> return True
SizeUniv -> return True
PiSort a s -> usableRel rel (a,s)
FunSort s1 s2 -> usableRel rel (s1,s2)
UnivSort s -> usableRel rel s
MetaS x es -> usableRel rel es
DefS d es -> usableRel rel $ Def d es
DummyS{} -> return True
instance UsableRelevance Level where
usableRel rel (Max _ ls) = usableRel rel ls
instance UsableRelevance PlusLevel where
usableRel rel (Plus _ l) = usableRel rel l
instance UsableRelevance LevelAtom where
usableRel rel l = case l of
MetaLevel m vs -> do
mrel <- getMetaRelevance <$> lookupMeta m
return (mrel `moreRelevant` rel) `and2M` usableRel rel vs
NeutralLevel _ v -> usableRel rel v
BlockedLevel _ v -> usableRel rel v
UnreducedLevel v -> usableRel rel v
instance UsableRelevance a => UsableRelevance [a] where
usableRel rel = andM . map (usableRel rel)
instance (UsableRelevance a, UsableRelevance b) => UsableRelevance (a,b) where
usableRel rel (a,b) = usableRel rel a `and2M` usableRel rel b
instance UsableRelevance a => UsableRelevance (Elim' a) where
usableRel rel (Apply a) = usableRel rel a
usableRel rel (Proj _ p) = do
prel <- relOfConst p
return $ prel `moreRelevant` rel
usableRel rel (IApply x y v) = allM [x,y,v] $ usableRel rel
instance UsableRelevance a => UsableRelevance (Arg a) where
usableRel rel (Arg info u) =
let rel' = getRelevance info
in usableRel (rel `composeRelevance` rel') u
instance UsableRelevance a => UsableRelevance (Dom a) where
usableRel rel Dom{unDom = u} = usableRel rel u
instance (Subst t a, UsableRelevance a) => UsableRelevance (Abs a) where
usableRel rel abs = underAbstraction_ abs $ \u -> usableRel rel u
class UsableModality a where
usableMod :: Modality -> a -> TCM Bool
instance UsableModality Term where
usableMod mod u = case u of
Var i vs -> do
imod <- getModality <$> domOfBV i
let ok = imod `moreUsableModality` mod
reportSDoc "tc.irr" 50 $
"Variable" <+> prettyTCM (var i) <+>
text ("has modality " ++ show imod ++ ", which is a " ++
(if ok then "" else "NOT ") ++ "more usable modality than " ++ show mod)
return ok `and2M` usableMod mod vs
Def f vs -> do
fmod <- modalityOfConst f
let ok = fmod `moreUsableModality` mod
reportSDoc "tc.irr" 50 $
"Definition" <+> prettyTCM (Def f []) <+>
text ("has modality " ++ show fmod ++ ", which is a " ++
(if ok then "" else "NOT ") ++ "more usable modality than " ++ show mod)
return ok `and2M` usableMod mod vs
Con c _ vs -> usableMod mod vs
Lit l -> return True
Lam _ v -> usableMod mod v
Pi a b -> usableMod mod (a,b)
Sort s -> usableMod mod s
Level l -> return True
MetaV m vs -> do
mmod <- getMetaModality <$> lookupMeta m
let ok = mmod `moreUsableModality` mod
reportSDoc "tc.irr" 50 $
"Metavariable" <+> prettyTCM (MetaV m []) <+>
text ("has modality " ++ show mmod ++ ", which is a " ++
(if ok then "" else "NOT ") ++ "more usable modality than " ++ show mod)
return ok `and2M` usableMod mod vs
DontCare v -> usableMod mod v
Dummy{} -> return True
instance UsableRelevance a => UsableModality (Type' a) where
usableMod mod (El _ t) = usableRel (getRelevance mod) t
instance UsableModality Sort where
usableMod mod s = usableRel (getRelevance mod) s
instance UsableModality Level where
usableMod mod (Max _ ls) = usableRel (getRelevance mod) ls
instance UsableModality a => UsableModality [a] where
usableMod mod = andM . map (usableMod mod)
instance (UsableModality a, UsableModality b) => UsableModality (a,b) where
usableMod mod (a,b) = usableMod mod a `and2M` usableMod mod b
instance UsableModality a => UsableModality (Elim' a) where
usableMod mod (Apply a) = usableMod mod a
usableMod mod (Proj _ p) = do
pmod <- modalityOfConst p
return $ pmod `moreUsableModality` mod
usableMod mod (IApply x y v) = allM [x,y,v] $ usableMod mod
instance UsableModality a => UsableModality (Arg a) where
usableMod mod (Arg info u) =
let mod' = getModality info
in usableMod (mod `composeModality` mod') u
instance UsableModality a => UsableModality (Dom a) where
usableMod mod Dom{unDom = u} = usableMod mod u
instance (Subst t a, UsableModality a) => UsableModality (Abs a) where
usableMod mod abs = underAbstraction_ abs $ \u -> usableMod mod u
isPropM :: (LensSort a, PrettyTCM a, MonadReduce m, MonadDebug m) => a -> m Bool
isPropM a = do
traceSDoc "tc.prop" 80 ("Is " <+> prettyTCM a <+> "of sort" <+> prettyTCM (getSort a) <+> "in Prop?") $ do
reduce (getSort a) <&> \case
Prop{} -> True
_ -> False
isIrrelevantOrPropM :: (LensRelevance a, LensSort a, PrettyTCM a, MonadReduce m, MonadDebug m) => a -> m Bool
isIrrelevantOrPropM x = return (isIrrelevant x) `or2M` isPropM x