{-# LANGUAGE CPP #-}
module Agda.TypeChecking.EtaContract where
import Control.Monad.Reader
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
#include "undefined.h"
import Agda.Utils.Impossible
data BinAppView = App Term (Arg Term)
| NoApp Term
binAppView :: Term -> BinAppView
binAppView t = case t of
Var i xs -> appE (Var i) xs
Def c xs -> appE (Def c) xs
Con c ci xs
| null (conFields c) -> appE (Con c ci) xs
| otherwise -> noApp
Lit _ -> noApp
Level _ -> noApp
Lam _ _ -> noApp
Pi _ _ -> noApp
Sort _ -> noApp
MetaV _ _ -> noApp
DontCare _ -> noApp
Dummy{} -> __IMPOSSIBLE__
where
noApp = NoApp t
app f [] = noApp
app f xs = App (f $ init xs) (last xs)
appE f [] = noApp
appE f xs
| Apply v <- last xs = App (f $ init xs) v
| otherwise = 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 = traverseTermM etaOnce
{-# SPECIALIZE etaOnce :: Term -> TCM Term #-}
{-# SPECIALIZE etaOnce :: Term -> ReduceM Term #-}
etaOnce :: (MonadTCEnv m, HasConstInfo m, HasOptions m) => Term -> m Term
etaOnce v = case v of
Lam i (Abs x b) -> etaLam i x b
Con c ci es -> do
etaCon c ci es etaContractRecord
v -> return v
etaCon :: (MonadTCEnv m, HasConstInfo m, HasOptions m)
=> ConHead
-> ConInfo
-> Elims
-> (QName -> ConHead -> ConInfo -> Args -> m Term)
-> m Term
etaCon c ci es cont = ignoreAbstractMode $ do
let fallback = return $ Con c ci $ es
r <- getConstructorData $ conName c
ifNotM (isEtaRecord r) fallback $ do
let Just args = allApplyElims es
cont r c ci args
etaLam :: (MonadTCEnv m, HasConstInfo m, HasOptions m)
=> ArgInfo
-> ArgName
-> Term
-> m Term
etaLam i x b = do
let fallback = return $ Lam i $ Abs x b
case binAppView b of
App u (Arg info v) -> do
tyty <- typeInType
if isVar0 tyty v
&& sameHiding i info
&& not (freeIn 0 u)
then return $ strengthen __IMPOSSIBLE__ u
else fallback
_ -> fallback
where
isVar0 _ (Var 0 []) = True
isVar0 True Level{} = True
isVar0 tyty (Level (Max [Plus 0 l])) = case l of
NeutralLevel _ v -> isVar0 tyty v
UnreducedLevel v -> isVar0 tyty v
BlockedLevel{} -> False
MetaLevel{} -> False
isVar0 _ _ = False