module Agda.TypeChecking.EtaContract where
import Agda.Syntax.Common
import Agda.Syntax.Internal
import Agda.Syntax.Internal.Generic
import Agda.TypeChecking.Substitute
import Agda.TypeChecking.Free
import Agda.TypeChecking.Monad
import Agda.TypeChecking.Reduce.Monad ()
import {-# SOURCE #-} Agda.TypeChecking.Records
import {-# SOURCE #-} Agda.TypeChecking.Datatypes
import Agda.Utils.Monad
import Agda.Utils.List (initLast)
import Agda.Utils.Impossible
data BinAppView = App Term (Arg Term)
| NoApp Term
binAppView :: Term -> BinAppView
binAppView :: Term -> BinAppView
binAppView Term
t = case Term
t of
Var Int
i Elims
xs -> (Elims -> Term) -> Elims -> BinAppView
appE (Int -> Elims -> Term
Var Int
i) Elims
xs
Def QName
c Elims
xs -> (Elims -> Term) -> Elims -> BinAppView
appE (QName -> Elims -> Term
Def QName
c) Elims
xs
Con ConHead
c ConInfo
ci Elims
xs
| DataOrRecord
IsData <- ConHead -> DataOrRecord
conDataRecord ConHead
c
-> (Elims -> Term) -> Elims -> BinAppView
appE (ConHead -> ConInfo -> Elims -> Term
Con ConHead
c ConInfo
ci) Elims
xs
| Bool
otherwise
-> BinAppView
noApp
Lit Literal
_ -> BinAppView
noApp
Level Level
_ -> BinAppView
noApp
Lam ArgInfo
_ Abs Term
_ -> BinAppView
noApp
Pi Dom Type
_ Abs Type
_ -> BinAppView
noApp
Sort Sort
_ -> BinAppView
noApp
MetaV MetaId
_ Elims
_ -> BinAppView
noApp
DontCare Term
_ -> BinAppView
noApp
Dummy{} -> forall a. HasCallStack => a
__IMPOSSIBLE__
where
noApp :: BinAppView
noApp = Term -> BinAppView
NoApp Term
t
appE :: (Elims -> Term) -> Elims -> BinAppView
appE Elims -> Term
f Elims
es0 | Just (Elims
es, Apply Arg Term
v) <- forall a. [a] -> Maybe ([a], a)
initLast Elims
es0 = Term -> Arg Term -> BinAppView
App (Elims -> Term
f Elims
es) Arg Term
v
appE Elims -> Term
_ Elims
_ = BinAppView
noApp
{-# SPECIALIZE etaContract :: TermLike a => a -> TCM a #-}
{-# SPECIALIZE etaContract :: TermLike a => a -> ReduceM a #-}
etaContract :: (MonadTCEnv m, HasConstInfo m, HasOptions m, TermLike a) => a -> m a
etaContract :: forall (m :: * -> *) a.
(MonadTCEnv m, HasConstInfo m, HasOptions m, TermLike a) =>
a -> m a
etaContract = forall a (m :: * -> *).
(TermLike a, Monad m) =>
(Term -> m Term) -> a -> m a
traverseTermM forall (m :: * -> *).
(MonadTCEnv m, HasConstInfo m, HasOptions m) =>
Term -> m Term
etaOnce
{-# SPECIALIZE etaOnce :: Term -> TCM Term #-}
{-# SPECIALIZE etaOnce :: Term -> ReduceM Term #-}
etaOnce :: (MonadTCEnv m, HasConstInfo m, HasOptions m) => Term -> m Term
etaOnce :: forall (m :: * -> *).
(MonadTCEnv m, HasConstInfo m, HasOptions m) =>
Term -> m Term
etaOnce = \case
Lam ArgInfo
i (Abs ArgName
x Term
b) -> forall (m :: * -> *).
(MonadTCEnv m, HasConstInfo m, HasOptions m) =>
ArgInfo -> ArgName -> Term -> m Term
etaLam ArgInfo
i ArgName
x Term
b
Con ConHead
c ConInfo
ci Elims
es -> forall (m :: * -> *).
(MonadTCEnv m, HasConstInfo m, HasOptions m) =>
ConHead
-> ConInfo
-> Elims
-> (QName -> ConHead -> ConInfo -> Args -> m Term)
-> m Term
etaCon ConHead
c ConInfo
ci Elims
es forall (m :: * -> *).
HasConstInfo m =>
QName -> ConHead -> ConInfo -> Args -> m Term
etaContractRecord
Term
v -> forall (m :: * -> *) a. Monad m => a -> m a
return Term
v
etaCon :: (MonadTCEnv m, HasConstInfo m, HasOptions m)
=> ConHead
-> ConInfo
-> Elims
-> (QName -> ConHead -> ConInfo -> Args -> m Term)
-> m Term
etaCon :: forall (m :: * -> *).
(MonadTCEnv m, HasConstInfo m, HasOptions m) =>
ConHead
-> ConInfo
-> Elims
-> (QName -> ConHead -> ConInfo -> Args -> m Term)
-> m Term
etaCon ConHead
c ConInfo
ci Elims
es QName -> ConHead -> ConInfo -> Args -> m Term
cont = forall (m :: * -> *) a. MonadTCEnv m => m a -> m a
ignoreAbstractMode forall a b. (a -> b) -> a -> b
$ do
let fallback :: m Term
fallback = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ConHead -> ConInfo -> Elims -> Term
Con ConHead
c ConInfo
ci Elims
es
QName
r <- forall (m :: * -> *). HasConstInfo m => QName -> m QName
getConstructorData forall a b. (a -> b) -> a -> b
$ ConHead -> QName
conName ConHead
c
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifNotM (forall (m :: * -> *). HasConstInfo m => QName -> m Bool
isEtaRecord QName
r) m Term
fallback forall a b. (a -> b) -> a -> b
$ do
let Just Args
args = forall a. [Elim' a] -> Maybe [Arg a]
allApplyElims Elims
es
QName -> ConHead -> ConInfo -> Args -> m Term
cont QName
r ConHead
c ConInfo
ci Args
args
etaLam :: (MonadTCEnv m, HasConstInfo m, HasOptions m)
=> ArgInfo
-> ArgName
-> Term
-> m Term
etaLam :: forall (m :: * -> *).
(MonadTCEnv m, HasConstInfo m, HasOptions m) =>
ArgInfo -> ArgName -> Term -> m Term
etaLam ArgInfo
i ArgName
x Term
b = do
let fallback :: m Term
fallback = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ArgInfo -> Abs Term -> Term
Lam ArgInfo
i forall a b. (a -> b) -> a -> b
$ forall a. ArgName -> a -> Abs a
Abs ArgName
x Term
b
case Term -> BinAppView
binAppView Term
b of
App Term
u (Arg ArgInfo
info Term
v) -> do
Bool
tyty <- forall (m :: * -> *). HasOptions m => m Bool
typeInType
if forall {t}. t -> Term -> Bool
isVar0 Bool
tyty Term
v
Bool -> Bool -> Bool
&& forall a b. (LensHiding a, LensHiding b) => a -> b -> Bool
sameHiding ArgInfo
i ArgInfo
info
Bool -> Bool -> Bool
&& forall a b. (LensModality a, LensModality b) => a -> b -> Bool
sameModality ArgInfo
i ArgInfo
info
Bool -> Bool -> Bool
&& Bool -> Bool
not (forall a. Free a => Int -> a -> Bool
freeIn Int
0 Term
u)
then forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. Subst a => Impossible -> a -> a
strengthen HasCallStack => Impossible
impossible Term
u
else m Term
fallback
BinAppView
_ -> m Term
fallback
where
isVar0 :: t -> Term -> Bool
isVar0 t
_ (Var Int
0 []) = Bool
True
isVar0 t
tyty (Level (Max Integer
0 [Plus Integer
0 Term
l])) = t -> Term -> Bool
isVar0 t
tyty Term
l
isVar0 t
_ Term
_ = Bool
False