{-# LANGUAGE PatternSynonyms #-}

module Agda.Compiler.Treeless.Erase
       ( eraseTerms
       , computeErasedConstructorArgs
       , isErasable
       ) where

import Control.Arrow (first, second)
import Control.Monad
import Control.Monad.State
import Data.Map (Map)
import qualified Data.Map as Map

import Agda.Syntax.Common
import Agda.Syntax.Internal as I
import Agda.Syntax.Abstract.Name (QName)
import Agda.Syntax.Position
import Agda.Syntax.Treeless
import Agda.Syntax.Literal

import Agda.TypeChecking.Substitute
import Agda.TypeChecking.Monad as I
import Agda.TypeChecking.Monad.Builtin
import Agda.TypeChecking.Telescope
import Agda.TypeChecking.Datatypes
import Agda.TypeChecking.Pretty
import Agda.TypeChecking.Primitive

import {-# SOURCE #-} Agda.Compiler.Backend
import Agda.Compiler.Treeless.Subst
import Agda.Compiler.Treeless.Unused

import Agda.Utils.Functor
import Agda.Utils.Lens
import Agda.Utils.Maybe
import Agda.Utils.Memo
import Agda.Utils.Monad
import Agda.Utils.Pretty (prettyShow)
import Agda.Utils.IntSet.Infinite (IntSet)
import qualified Agda.Utils.IntSet.Infinite as IntSet

import Agda.Utils.Impossible

-- | State of the eraser.
data ESt = ESt
  { ESt -> Map QName FunInfo
_funMap  :: Map QName FunInfo
      -- ^ Memoize computed `FunInfo` for functions/constructors/... `QName`.
  , ESt -> Map QName TypeInfo
_typeMap :: Map QName TypeInfo
      -- ^ Memoize computed `TypeInfo` for data/record types `QName`.
  }

funMap :: Lens' (Map QName FunInfo) ESt
funMap :: (Map QName FunInfo -> f (Map QName FunInfo)) -> ESt -> f ESt
funMap Map QName FunInfo -> f (Map QName FunInfo)
f ESt
r = Map QName FunInfo -> f (Map QName FunInfo)
f (ESt -> Map QName FunInfo
_funMap ESt
r) f (Map QName FunInfo) -> (Map QName FunInfo -> ESt) -> f ESt
forall (m :: * -> *) a b. Functor m => m a -> (a -> b) -> m b
<&> \ Map QName FunInfo
a -> ESt
r { _funMap :: Map QName FunInfo
_funMap = Map QName FunInfo
a }

typeMap :: Lens' (Map QName TypeInfo) ESt
typeMap :: (Map QName TypeInfo -> f (Map QName TypeInfo)) -> ESt -> f ESt
typeMap Map QName TypeInfo -> f (Map QName TypeInfo)
f ESt
r = Map QName TypeInfo -> f (Map QName TypeInfo)
f (ESt -> Map QName TypeInfo
_typeMap ESt
r) f (Map QName TypeInfo) -> (Map QName TypeInfo -> ESt) -> f ESt
forall (m :: * -> *) a b. Functor m => m a -> (a -> b) -> m b
<&> \ Map QName TypeInfo
a -> ESt
r { _typeMap :: Map QName TypeInfo
_typeMap = Map QName TypeInfo
a }

-- | Eraser monad.
type E = StateT ESt TCM

runE :: E a -> TCM a
runE :: E a -> TCM a
runE E a
m = E a -> ESt -> TCM a
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
evalStateT E a
m (Map QName FunInfo -> Map QName TypeInfo -> ESt
ESt Map QName FunInfo
forall k a. Map k a
Map.empty Map QName TypeInfo
forall k a. Map k a
Map.empty)

-- | Takes the name of the data/record type.
computeErasedConstructorArgs :: QName -> TCM ()
computeErasedConstructorArgs :: QName -> TCM ()
computeErasedConstructorArgs QName
d = do
  [QName]
cs <- QName -> TCM [QName]
getConstructors QName
d
  E () -> TCM ()
forall a. E a -> TCM a
runE (E () -> TCM ()) -> E () -> TCM ()
forall a b. (a -> b) -> a -> b
$ (QName -> StateT ESt TCM FunInfo) -> [QName] -> E ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ QName -> StateT ESt TCM FunInfo
getFunInfo [QName]
cs

eraseTerms :: QName -> EvaluationStrategy -> TTerm -> TCM TTerm
eraseTerms :: QName -> EvaluationStrategy -> TTerm -> TCM TTerm
eraseTerms QName
q EvaluationStrategy
eval TTerm
t = QName -> TTerm -> TCM [Bool]
usedArguments QName
q TTerm
t TCM [Bool] -> TCM TTerm -> TCM TTerm
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> E TTerm -> TCM TTerm
forall a. E a -> TCM a
runE (QName -> TTerm -> E TTerm
eraseTop QName
q TTerm
t)
  where
    eraseTop :: QName -> TTerm -> E TTerm
eraseTop QName
q TTerm
t = do
      ([TypeInfo]
_, TypeInfo
h) <- QName -> StateT ESt TCM FunInfo
getFunInfo QName
q
      case TypeInfo
h of
        TypeInfo
Erasable -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
TErased
        TypeInfo
Empty    -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
TErased
        TypeInfo
_        -> TTerm -> E TTerm
erase TTerm
t

    erase :: TTerm -> E TTerm
erase TTerm
t = case TTerm -> (TTerm, [TTerm])
tAppView TTerm
t of

      (TCon QName
c, [TTerm]
vs) -> do
        ([TypeInfo]
rs, TypeInfo
h) <- QName -> StateT ESt TCM FunInfo
getFunInfo QName
c
        Bool -> E () -> E ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ([TypeInfo] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [TypeInfo]
rs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< [TTerm] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [TTerm]
vs) E ()
forall a. HasCallStack => a
__IMPOSSIBLE__
        case TypeInfo
h of
          TypeInfo
Erasable -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
TErased
          TypeInfo
Empty    -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
TErased
          TypeInfo
_        -> TTerm -> [TTerm] -> TTerm
tApp (QName -> TTerm
TCon QName
c) ([TTerm] -> TTerm) -> StateT ESt TCM [TTerm] -> E TTerm
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (TypeInfo -> TTerm -> E TTerm)
-> [TypeInfo] -> [TTerm] -> StateT ESt TCM [TTerm]
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m [c]
zipWithM TypeInfo -> TTerm -> E TTerm
eraseRel [TypeInfo]
rs [TTerm]
vs

      (TDef QName
f, [TTerm]
vs) -> do
        ([TypeInfo]
rs, TypeInfo
h) <- QName -> StateT ESt TCM FunInfo
getFunInfo QName
f
        case TypeInfo
h of
          TypeInfo
Erasable -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
TErased
          TypeInfo
Empty    -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
TErased
          TypeInfo
_        -> TTerm -> [TTerm] -> TTerm
tApp (QName -> TTerm
TDef QName
f) ([TTerm] -> TTerm) -> StateT ESt TCM [TTerm] -> E TTerm
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (TypeInfo -> TTerm -> E TTerm)
-> [TypeInfo] -> [TTerm] -> StateT ESt TCM [TTerm]
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m [c]
zipWithM TypeInfo -> TTerm -> E TTerm
eraseRel ([TypeInfo]
rs [TypeInfo] -> [TypeInfo] -> [TypeInfo]
forall a. [a] -> [a] -> [a]
++ TypeInfo -> [TypeInfo]
forall a. a -> [a]
repeat TypeInfo
NotErasable) [TTerm]
vs

      (TTerm, [TTerm])
_ -> case TTerm
t of
        TVar{}         -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
t
        TDef{}         -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
t
        TPrim{}        -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
t
        TLit{}         -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
t
        TCon{}         -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
t
        TApp TTerm
f [TTerm]
es      -> TTerm -> [TTerm] -> TTerm
tApp (TTerm -> [TTerm] -> TTerm)
-> E TTerm -> StateT ESt TCM ([TTerm] -> TTerm)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TTerm -> E TTerm
erase TTerm
f StateT ESt TCM ([TTerm] -> TTerm)
-> StateT ESt TCM [TTerm] -> E TTerm
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (TTerm -> E TTerm) -> [TTerm] -> StateT ESt TCM [TTerm]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM TTerm -> E TTerm
erase [TTerm]
es
        TLam TTerm
b         -> TTerm -> TTerm
tLam (TTerm -> TTerm) -> E TTerm -> E TTerm
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TTerm -> E TTerm
erase TTerm
b
        TLet TTerm
e TTerm
b       -> do
          TTerm
e <- TTerm -> E TTerm
erase TTerm
e
          if TTerm -> Bool
isErased TTerm
e
            then case TTerm
b of
                   TCase Int
0 CaseInfo
_ TTerm
_ [TAlt]
_ -> TTerm -> TTerm -> TTerm
tLet TTerm
TErased (TTerm -> TTerm) -> E TTerm -> E TTerm
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TTerm -> E TTerm
erase TTerm
b
                   TTerm
_             -> TTerm -> E TTerm
erase (TTerm -> E TTerm) -> TTerm -> E TTerm
forall a b. (a -> b) -> a -> b
$ Int -> TTerm -> TTerm -> TTerm
forall t a. Subst t a => Int -> t -> a -> a
subst Int
0 TTerm
TErased TTerm
b
            else TTerm -> TTerm -> TTerm
tLet TTerm
e (TTerm -> TTerm) -> E TTerm -> E TTerm
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TTerm -> E TTerm
erase TTerm
b
        TCase Int
x CaseInfo
t TTerm
d [TAlt]
bs -> do
          (TTerm
d, [TAlt]
bs) <- Int -> CaseType -> TTerm -> [TAlt] -> E (TTerm, [TAlt])
pruneUnreachable Int
x (CaseInfo -> CaseType
caseType CaseInfo
t) TTerm
d [TAlt]
bs
          TTerm
d       <- TTerm -> E TTerm
erase TTerm
d
          [TAlt]
bs      <- (TAlt -> StateT ESt TCM TAlt) -> [TAlt] -> StateT ESt TCM [TAlt]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM TAlt -> StateT ESt TCM TAlt
eraseAlt [TAlt]
bs
          Int -> CaseInfo -> TTerm -> [TAlt] -> E TTerm
tCase Int
x CaseInfo
t TTerm
d [TAlt]
bs

        TTerm
TUnit          -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
t
        TTerm
TSort          -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
t
        TTerm
TErased        -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
t
        TError{}       -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
t
        TCoerce TTerm
e      -> TTerm -> TTerm
TCoerce (TTerm -> TTerm) -> E TTerm -> E TTerm
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TTerm -> E TTerm
erase TTerm
e

    -- #3380: this is not safe for strict backends
    tLam :: TTerm -> TTerm
tLam TTerm
TErased | EvaluationStrategy
eval EvaluationStrategy -> EvaluationStrategy -> Bool
forall a. Eq a => a -> a -> Bool
== EvaluationStrategy
LazyEvaluation = TTerm
TErased
    tLam TTerm
t                                = TTerm -> TTerm
TLam TTerm
t

    tLet :: TTerm -> TTerm -> TTerm
tLet TTerm
e TTerm
b
      | Int -> TTerm -> Bool
forall a. HasFree a => Int -> a -> Bool
freeIn Int
0 TTerm
b = TTerm -> TTerm -> TTerm
TLet TTerm
e TTerm
b
      | Bool
otherwise  = Empty -> TTerm -> TTerm
forall t a. Subst t a => Empty -> a -> a
strengthen Empty
forall a. HasCallStack => a
__IMPOSSIBLE__ TTerm
b

    tApp :: TTerm -> [TTerm] -> TTerm
tApp TTerm
f []                  = TTerm
f
    tApp TTerm
TErased [TTerm]
_             = TTerm
TErased
    tApp TTerm
f [TTerm]
_ | TTerm -> Bool
forall a. Unreachable a => a -> Bool
isUnreachable TTerm
f = TTerm
tUnreachable
    tApp TTerm
f [TTerm]
es                  = TTerm -> [TTerm] -> TTerm
mkTApp TTerm
f [TTerm]
es

    tCase :: Int -> CaseInfo -> TTerm -> [TAlt] -> E TTerm
tCase Int
x CaseInfo
t TTerm
d [TAlt]
bs
      | TTerm -> Bool
isErased TTerm
d Bool -> Bool -> Bool
&& (TAlt -> Bool) -> [TAlt] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (TTerm -> Bool
isErased (TTerm -> Bool) -> (TAlt -> TTerm) -> TAlt -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TAlt -> TTerm
aBody) [TAlt]
bs = TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
TErased
      | Bool
otherwise = case [TAlt]
bs of
        [TACon QName
c Int
a TTerm
b] -> do
          TypeInfo
h <- FunInfo -> TypeInfo
forall a b. (a, b) -> b
snd (FunInfo -> TypeInfo)
-> StateT ESt TCM FunInfo -> StateT ESt TCM TypeInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> QName -> StateT ESt TCM FunInfo
getFunInfo QName
c
          case TypeInfo
h of
            TypeInfo
NotErasable -> E TTerm
noerase
            TypeInfo
Empty       -> TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
TErased
            TypeInfo
Erasable    -> (if Int
a Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure else TTerm -> E TTerm
erase) (TTerm -> E TTerm) -> TTerm -> E TTerm
forall a b. (a -> b) -> a -> b
$ Substitution' TTerm -> TTerm -> TTerm
forall t a. Subst t a => Substitution' t -> a -> a
applySubst (Int -> TTerm -> [TTerm]
forall a. Int -> a -> [a]
replicate Int
a TTerm
TErased [TTerm] -> Substitution' TTerm -> Substitution' TTerm
forall a. DeBruijn a => [a] -> Substitution' a -> Substitution' a
++# Substitution' TTerm
forall a. Substitution' a
idS) TTerm
b
                              -- might enable more erasure
        [TAlt]
_ -> E TTerm
noerase
      where
        noerase :: E TTerm
noerase = TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TTerm -> E TTerm) -> TTerm -> E TTerm
forall a b. (a -> b) -> a -> b
$ Int -> CaseInfo -> TTerm -> [TAlt] -> TTerm
TCase Int
x CaseInfo
t TTerm
d [TAlt]
bs

    isErased :: TTerm -> Bool
isErased TTerm
t = TTerm
t TTerm -> TTerm -> Bool
forall a. Eq a => a -> a -> Bool
== TTerm
TErased Bool -> Bool -> Bool
|| TTerm -> Bool
forall a. Unreachable a => a -> Bool
isUnreachable TTerm
t

    eraseRel :: TypeInfo -> TTerm -> E TTerm
eraseRel TypeInfo
r TTerm
t | TypeInfo -> Bool
erasable TypeInfo
r = TTerm -> E TTerm
forall (f :: * -> *) a. Applicative f => a -> f a
pure TTerm
TErased
                 | Bool
otherwise  = TTerm -> E TTerm
erase TTerm
t

    eraseAlt :: TAlt -> StateT ESt TCM TAlt
eraseAlt TAlt
a = case TAlt
a of
      TALit Literal
l TTerm
b   -> Literal -> TTerm -> TAlt
TALit Literal
l   (TTerm -> TAlt) -> E TTerm -> StateT ESt TCM TAlt
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TTerm -> E TTerm
erase TTerm
b
      TACon QName
c Int
a TTerm
b -> do
        [Bool]
rs <- (TypeInfo -> Bool) -> [TypeInfo] -> [Bool]
forall a b. (a -> b) -> [a] -> [b]
map TypeInfo -> Bool
erasable ([TypeInfo] -> [Bool])
-> (FunInfo -> [TypeInfo]) -> FunInfo -> [Bool]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunInfo -> [TypeInfo]
forall a b. (a, b) -> a
fst (FunInfo -> [Bool])
-> StateT ESt TCM FunInfo -> StateT ESt TCM [Bool]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> QName -> StateT ESt TCM FunInfo
getFunInfo QName
c
        let sub :: Substitution' TTerm
sub = (Bool -> Substitution' TTerm -> Substitution' TTerm)
-> Substitution' TTerm -> [Bool] -> Substitution' TTerm
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\ Bool
e -> if Bool
e then (TTerm
TErased TTerm -> Substitution' TTerm -> Substitution' TTerm
forall a. a -> Substitution' a -> Substitution' a
:#) (Substitution' TTerm -> Substitution' TTerm)
-> (Substitution' TTerm -> Substitution' TTerm)
-> Substitution' TTerm
-> Substitution' TTerm
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Substitution' TTerm -> Substitution' TTerm
forall a. Int -> Substitution' a -> Substitution' a
wkS Int
1 else Int -> Substitution' TTerm -> Substitution' TTerm
forall a. Int -> Substitution' a -> Substitution' a
liftS Int
1) Substitution' TTerm
forall a. Substitution' a
idS ([Bool] -> Substitution' TTerm) -> [Bool] -> Substitution' TTerm
forall a b. (a -> b) -> a -> b
$ [Bool] -> [Bool]
forall a. [a] -> [a]
reverse [Bool]
rs
        QName -> Int -> TTerm -> TAlt
TACon QName
c Int
a (TTerm -> TAlt) -> E TTerm -> StateT ESt TCM TAlt
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TTerm -> E TTerm
erase (Substitution' TTerm -> TTerm -> TTerm
forall t a. Subst t a => Substitution' t -> a -> a
applySubst Substitution' TTerm
sub TTerm
b)
      TAGuard TTerm
g TTerm
b -> TTerm -> TTerm -> TAlt
TAGuard   (TTerm -> TTerm -> TAlt)
-> E TTerm -> StateT ESt TCM (TTerm -> TAlt)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TTerm -> E TTerm
erase TTerm
g StateT ESt TCM (TTerm -> TAlt) -> E TTerm -> StateT ESt TCM TAlt
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> TTerm -> E TTerm
erase TTerm
b

-- | Doesn't have any type information (other than the name of the data type),
--   so we can't do better than checking if all constructors are present.
pruneUnreachable :: Int -> CaseType -> TTerm -> [TAlt] -> E (TTerm, [TAlt])
pruneUnreachable :: Int -> CaseType -> TTerm -> [TAlt] -> E (TTerm, [TAlt])
pruneUnreachable Int
_ (CTData QName
q) TTerm
d [TAlt]
bs = do
  [QName]
cs <- TCM [QName] -> StateT ESt TCM [QName]
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCM [QName] -> StateT ESt TCM [QName])
-> TCM [QName] -> StateT ESt TCM [QName]
forall a b. (a -> b) -> a -> b
$ QName -> TCM [QName]
getConstructors QName
q
  let complete :: Bool
complete =[QName] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [QName]
cs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [TAlt] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ TAlt
b | b :: TAlt
b@TACon{} <- [TAlt]
bs ]
  let d' :: TTerm
d' | Bool
complete  = TTerm
tUnreachable
         | Bool
otherwise = TTerm
d
  (TTerm, [TAlt]) -> E (TTerm, [TAlt])
forall (m :: * -> *) a. Monad m => a -> m a
return (TTerm
d', [TAlt]
bs)
pruneUnreachable Int
x CaseType
CTNat TTerm
d [TAlt]
bs = (TTerm, [TAlt]) -> E (TTerm, [TAlt])
forall (m :: * -> *) a. Monad m => a -> m a
return ((TTerm, [TAlt]) -> E (TTerm, [TAlt]))
-> (TTerm, [TAlt]) -> E (TTerm, [TAlt])
forall a b. (a -> b) -> a -> b
$ Int -> TTerm -> [TAlt] -> IntSet -> (TTerm, [TAlt])
pruneIntCase Int
x TTerm
d [TAlt]
bs (Integer -> IntSet
IntSet.below Integer
0)
pruneUnreachable Int
x CaseType
CTInt TTerm
d [TAlt]
bs = (TTerm, [TAlt]) -> E (TTerm, [TAlt])
forall (m :: * -> *) a. Monad m => a -> m a
return ((TTerm, [TAlt]) -> E (TTerm, [TAlt]))
-> (TTerm, [TAlt]) -> E (TTerm, [TAlt])
forall a b. (a -> b) -> a -> b
$ Int -> TTerm -> [TAlt] -> IntSet -> (TTerm, [TAlt])
pruneIntCase Int
x TTerm
d [TAlt]
bs IntSet
IntSet.empty
pruneUnreachable Int
_ CaseType
_ TTerm
d [TAlt]
bs = (TTerm, [TAlt]) -> E (TTerm, [TAlt])
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TTerm
d, [TAlt]
bs)

-- These are the guards we generate for Int/Nat pattern matching
pattern Below :: Range -> Int -> Integer -> TTerm
pattern $bBelow :: Range -> Int -> Integer -> TTerm
$mBelow :: forall r.
TTerm -> (Range -> Int -> Integer -> r) -> (Void# -> r) -> r
Below r x n = TApp (TPrim PLt)  [TVar x, TLit (LitNat r n)]

pattern Above :: Range -> Int -> Integer -> TTerm
pattern $bAbove :: Range -> Int -> Integer -> TTerm
$mAbove :: forall r.
TTerm -> (Range -> Int -> Integer -> r) -> (Void# -> r) -> r
Above r x n = TApp (TPrim PGeq) [TVar x, TLit (LitNat r n)]

-- | Strip unreachable clauses (replace by tUnreachable for the default).
--   Fourth argument is the set of ints covered so far.
pruneIntCase :: Int -> TTerm -> [TAlt] -> IntSet -> (TTerm, [TAlt])
pruneIntCase :: Int -> TTerm -> [TAlt] -> IntSet -> (TTerm, [TAlt])
pruneIntCase Int
x TTerm
d [TAlt]
bs IntSet
cover = [TAlt] -> IntSet -> (TTerm, [TAlt])
go [TAlt]
bs IntSet
cover
  where
    go :: [TAlt] -> IntSet -> (TTerm, [TAlt])
go [] IntSet
cover
      | IntSet
cover IntSet -> IntSet -> Bool
forall a. Eq a => a -> a -> Bool
== IntSet
IntSet.full = (TTerm
tUnreachable, [])
      | Bool
otherwise            = (TTerm
d, [])
    go (TAlt
b : [TAlt]
bs) IntSet
cover =
      case TAlt
b of
        TAGuard (Below Range
_ Int
y Integer
n) TTerm
_ | Int
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
y -> IntSet -> (TTerm, [TAlt])
rec (Integer -> IntSet
IntSet.below Integer
n)
        TAGuard (Above Range
_ Int
y Integer
n) TTerm
_ | Int
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
y -> IntSet -> (TTerm, [TAlt])
rec (Integer -> IntSet
IntSet.above Integer
n)
        TALit (LitNat Range
_ Integer
n) TTerm
_             -> IntSet -> (TTerm, [TAlt])
rec (Integer -> IntSet
IntSet.singleton Integer
n)
        TAlt
_                                -> ([TAlt] -> [TAlt]) -> (TTerm, [TAlt]) -> (TTerm, [TAlt])
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second (TAlt
b TAlt -> [TAlt] -> [TAlt]
forall a. a -> [a] -> [a]
:) ((TTerm, [TAlt]) -> (TTerm, [TAlt]))
-> (TTerm, [TAlt]) -> (TTerm, [TAlt])
forall a b. (a -> b) -> a -> b
$ [TAlt] -> IntSet -> (TTerm, [TAlt])
go [TAlt]
bs IntSet
cover
      where
        rec :: IntSet -> (TTerm, [TAlt])
rec IntSet
this = ([TAlt] -> [TAlt]) -> (TTerm, [TAlt]) -> (TTerm, [TAlt])
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second [TAlt] -> [TAlt]
addAlt ((TTerm, [TAlt]) -> (TTerm, [TAlt]))
-> (TTerm, [TAlt]) -> (TTerm, [TAlt])
forall a b. (a -> b) -> a -> b
$ [TAlt] -> IntSet -> (TTerm, [TAlt])
go [TAlt]
bs IntSet
cover'
          where
            this' :: IntSet
this'  = IntSet -> IntSet -> IntSet
IntSet.difference IntSet
this IntSet
cover
            cover' :: IntSet
cover' = IntSet
this' IntSet -> IntSet -> IntSet
forall a. Semigroup a => a -> a -> a
<> IntSet
cover
            addAlt :: [TAlt] -> [TAlt]
addAlt = case IntSet -> Maybe [Integer]
IntSet.toFiniteList IntSet
this' of
                       Just []  -> [TAlt] -> [TAlt]
forall a. a -> a
id                                     -- unreachable case
                       Just [Integer
n] -> (Literal -> TTerm -> TAlt
TALit (Range -> Integer -> Literal
LitNat Range
forall a. Range' a
noRange Integer
n) (TAlt -> TTerm
aBody TAlt
b) TAlt -> [TAlt] -> [TAlt]
forall a. a -> [a] -> [a]
:) -- possibly refined case
                       Maybe [Integer]
_        -> (TAlt
b TAlt -> [TAlt] -> [TAlt]
forall a. a -> [a] -> [a]
:)                                  -- unchanged case

data TypeInfo = Empty | Erasable | NotErasable
  deriving (TypeInfo -> TypeInfo -> Bool
(TypeInfo -> TypeInfo -> Bool)
-> (TypeInfo -> TypeInfo -> Bool) -> Eq TypeInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TypeInfo -> TypeInfo -> Bool
$c/= :: TypeInfo -> TypeInfo -> Bool
== :: TypeInfo -> TypeInfo -> Bool
$c== :: TypeInfo -> TypeInfo -> Bool
Eq, Int -> TypeInfo -> ShowS
[TypeInfo] -> ShowS
TypeInfo -> String
(Int -> TypeInfo -> ShowS)
-> (TypeInfo -> String) -> ([TypeInfo] -> ShowS) -> Show TypeInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TypeInfo] -> ShowS
$cshowList :: [TypeInfo] -> ShowS
show :: TypeInfo -> String
$cshow :: TypeInfo -> String
showsPrec :: Int -> TypeInfo -> ShowS
$cshowsPrec :: Int -> TypeInfo -> ShowS
Show)

sumTypeInfo :: [TypeInfo] -> TypeInfo
sumTypeInfo :: [TypeInfo] -> TypeInfo
sumTypeInfo [TypeInfo]
is = (TypeInfo -> TypeInfo -> TypeInfo)
-> TypeInfo -> [TypeInfo] -> TypeInfo
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr TypeInfo -> TypeInfo -> TypeInfo
plus TypeInfo
Empty [TypeInfo]
is
  where
    plus :: TypeInfo -> TypeInfo -> TypeInfo
plus TypeInfo
Empty       TypeInfo
r           = TypeInfo
r
    plus TypeInfo
r           TypeInfo
Empty       = TypeInfo
r
    plus TypeInfo
Erasable    TypeInfo
r           = TypeInfo
r
    plus TypeInfo
r           TypeInfo
Erasable    = TypeInfo
r
    plus TypeInfo
NotErasable TypeInfo
NotErasable = TypeInfo
NotErasable

erasable :: TypeInfo -> Bool
erasable :: TypeInfo -> Bool
erasable TypeInfo
Erasable    = Bool
True
erasable TypeInfo
Empty       = Bool
True
erasable TypeInfo
NotErasable = Bool
False

type FunInfo = ([TypeInfo], TypeInfo)

getFunInfo :: QName -> E FunInfo
getFunInfo :: QName -> StateT ESt TCM FunInfo
getFunInfo QName
q = Lens' (Maybe FunInfo) ESt
-> StateT ESt TCM FunInfo -> StateT ESt TCM FunInfo
forall s (m :: * -> *) a.
MonadState s m =>
Lens' (Maybe a) s -> m a -> m a
memo ((Map QName FunInfo -> f (Map QName FunInfo)) -> ESt -> f ESt
Lens' (Map QName FunInfo) ESt
funMap ((Map QName FunInfo -> f (Map QName FunInfo)) -> ESt -> f ESt)
-> ((Maybe FunInfo -> f (Maybe FunInfo))
    -> Map QName FunInfo -> f (Map QName FunInfo))
-> (Maybe FunInfo -> f (Maybe FunInfo))
-> ESt
-> f ESt
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QName -> Lens' (Maybe FunInfo) (Map QName FunInfo)
forall k v. Ord k => k -> Lens' (Maybe v) (Map k v)
key QName
q) (StateT ESt TCM FunInfo -> StateT ESt TCM FunInfo)
-> StateT ESt TCM FunInfo -> StateT ESt TCM FunInfo
forall a b. (a -> b) -> a -> b
$ QName -> StateT ESt TCM FunInfo
getInfo QName
q
  where
    getInfo :: QName -> E FunInfo
    getInfo :: QName -> StateT ESt TCM FunInfo
getInfo QName
q = do
      ([TypeInfo]
rs, Type
t) <- do
        (ListTel
tel, Type
t) <- TCMT IO (ListTel, Type) -> StateT ESt TCM (ListTel, Type)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCMT IO (ListTel, Type) -> StateT ESt TCM (ListTel, Type))
-> TCMT IO (ListTel, Type) -> StateT ESt TCM (ListTel, Type)
forall a b. (a -> b) -> a -> b
$ QName -> TCMT IO (ListTel, Type)
typeWithoutParams QName
q
        [TypeInfo]
is     <- (Dom' Term (String, Type) -> StateT ESt TCM TypeInfo)
-> ListTel -> StateT ESt TCM [TypeInfo]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Type -> StateT ESt TCM TypeInfo
getTypeInfo (Type -> StateT ESt TCM TypeInfo)
-> (Dom' Term (String, Type) -> Type)
-> Dom' Term (String, Type)
-> StateT ESt TCM TypeInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, Type) -> Type
forall a b. (a, b) -> b
snd ((String, Type) -> Type)
-> (Dom' Term (String, Type) -> (String, Type))
-> Dom' Term (String, Type)
-> Type
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dom' Term (String, Type) -> (String, Type)
forall (t :: * -> *) a. Decoration t => t a -> a
dget) ListTel
tel
        [Bool]
used   <- TCM [Bool] -> StateT ESt TCM [Bool]
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCM [Bool] -> StateT ESt TCM [Bool])
-> TCM [Bool] -> StateT ESt TCM [Bool]
forall a b. (a -> b) -> a -> b
$ ([Bool] -> [Bool] -> [Bool]
forall a. [a] -> [a] -> [a]
++ Bool -> [Bool]
forall a. a -> [a]
repeat Bool
True) ([Bool] -> [Bool]) -> TCM [Bool] -> TCM [Bool]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> QName -> TCM [Bool]
getCompiledArgUse QName
q
        [IsForced]
forced <- TCM [IsForced] -> StateT ESt TCM [IsForced]
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCM [IsForced] -> StateT ESt TCM [IsForced])
-> TCM [IsForced] -> StateT ESt TCM [IsForced]
forall a b. (a -> b) -> a -> b
$ ([IsForced] -> [IsForced] -> [IsForced]
forall a. [a] -> [a] -> [a]
++ IsForced -> [IsForced]
forall a. a -> [a]
repeat IsForced
NotForced) ([IsForced] -> [IsForced]) -> TCM [IsForced] -> TCM [IsForced]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> QName -> TCM [IsForced]
forall (m :: * -> *). HasConstInfo m => QName -> m [IsForced]
getForcedArgs QName
q
        ([TypeInfo], Type) -> StateT ESt TCM ([TypeInfo], Type)
forall (m :: * -> *) a. Monad m => a -> m a
return ((Dom' Term (String, Type)
 -> (IsForced, Bool) -> TypeInfo -> TypeInfo)
-> ListTel -> [(IsForced, Bool)] -> [TypeInfo] -> [TypeInfo]
forall a b c d. (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
zipWith3 ((IsForced -> Bool -> TypeInfo -> TypeInfo)
-> (IsForced, Bool) -> TypeInfo -> TypeInfo
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((IsForced -> Bool -> TypeInfo -> TypeInfo)
 -> (IsForced, Bool) -> TypeInfo -> TypeInfo)
-> (Dom' Term (String, Type)
    -> IsForced -> Bool -> TypeInfo -> TypeInfo)
-> Dom' Term (String, Type)
-> (IsForced, Bool)
-> TypeInfo
-> TypeInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Modality -> IsForced -> Bool -> TypeInfo -> TypeInfo
mkR (Modality -> IsForced -> Bool -> TypeInfo -> TypeInfo)
-> (Dom' Term (String, Type) -> Modality)
-> Dom' Term (String, Type)
-> IsForced
-> Bool
-> TypeInfo
-> TypeInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dom' Term (String, Type) -> Modality
forall a. LensModality a => a -> Modality
getModality) ListTel
tel ([IsForced] -> [Bool] -> [(IsForced, Bool)]
forall a b. [a] -> [b] -> [(a, b)]
zip [IsForced]
forced [Bool]
used) [TypeInfo]
is, Type
t)
      TypeInfo
h <- if QName -> Bool
isAbsurdLambdaName QName
q then TypeInfo -> StateT ESt TCM TypeInfo
forall (f :: * -> *) a. Applicative f => a -> f a
pure TypeInfo
Erasable else Type -> StateT ESt TCM TypeInfo
getTypeInfo Type
t
      TCM () -> E ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCM () -> E ()) -> TCM () -> E ()
forall a b. (a -> b) -> a -> b
$ String -> Int -> String -> TCM ()
forall (m :: * -> *).
MonadDebug m =>
String -> Int -> String -> m ()
reportSLn String
"treeless.opt.erase.info" Int
50 (String -> TCM ()) -> String -> TCM ()
forall a b. (a -> b) -> a -> b
$ String
"type info for " String -> ShowS
forall a. [a] -> [a] -> [a]
++ QName -> String
forall a. Pretty a => a -> String
prettyShow QName
q String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ [TypeInfo] -> String
forall a. Show a => a -> String
show [TypeInfo]
rs String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" -> " String -> ShowS
forall a. [a] -> [a] -> [a]
++ TypeInfo -> String
forall a. Show a => a -> String
show TypeInfo
h
      TCM () -> E ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCM () -> E ()) -> TCM () -> E ()
forall a b. (a -> b) -> a -> b
$ QName -> [Bool] -> TCM ()
setErasedConArgs QName
q ([Bool] -> TCM ()) -> [Bool] -> TCM ()
forall a b. (a -> b) -> a -> b
$ (TypeInfo -> Bool) -> [TypeInfo] -> [Bool]
forall a b. (a -> b) -> [a] -> [b]
map TypeInfo -> Bool
erasable [TypeInfo]
rs
      FunInfo -> StateT ESt TCM FunInfo
forall (m :: * -> *) a. Monad m => a -> m a
return ([TypeInfo]
rs, TypeInfo
h)

    -- Treat empty, erasable, or unused arguments as Erasable
    mkR :: Modality -> IsForced -> Bool -> TypeInfo -> TypeInfo
    mkR :: Modality -> IsForced -> Bool -> TypeInfo -> TypeInfo
mkR Modality
m IsForced
f Bool
b TypeInfo
i
      | Bool -> Bool
not (Modality -> Bool
forall a. LensModality a => a -> Bool
usableModality Modality
m) = TypeInfo
Erasable
      | Bool -> Bool
not Bool
b                  = TypeInfo
Erasable
      | IsForced
Forced <- IsForced
f            = TypeInfo
Erasable
      | Bool
otherwise              = TypeInfo
i

isErasable :: QName -> TCM Bool
isErasable :: QName -> TCM Bool
isErasable QName
qn =
  -- The active backend should be set
  TCMT IO (Maybe String)
-> TCM Bool -> (String -> TCM Bool) -> TCM Bool
forall (m :: * -> *) a b.
Monad m =>
m (Maybe a) -> m b -> (a -> m b) -> m b
caseMaybeM (Lens' (Maybe String) TCEnv -> TCMT IO (Maybe String)
forall (m :: * -> *) a. MonadTCEnv m => Lens' a TCEnv -> m a
viewTC Lens' (Maybe String) TCEnv
eActiveBackendName) TCM Bool
forall a. HasCallStack => a
__IMPOSSIBLE__ ((String -> TCM Bool) -> TCM Bool)
-> (String -> TCM Bool) -> TCM Bool
forall a b. (a -> b) -> a -> b
$ \ String
bname ->
  -- However it may not be part of the set of available backends
  -- in which case we default to not erasable to avoid false negatives.
  TCMT IO (Maybe Backend)
-> TCM Bool -> (Backend -> TCM Bool) -> TCM Bool
forall (m :: * -> *) a b.
Monad m =>
m (Maybe a) -> m b -> (a -> m b) -> m b
caseMaybeM (String -> TCMT IO (Maybe Backend)
lookupBackend String
bname)       (Bool -> TCM Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False)   ((Backend -> TCM Bool) -> TCM Bool)
-> (Backend -> TCM Bool) -> TCM Bool
forall a b. (a -> b) -> a -> b
$ \ Backend
_ ->
  TypeInfo -> Bool
erasable (TypeInfo -> Bool) -> (FunInfo -> TypeInfo) -> FunInfo -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunInfo -> TypeInfo
forall a b. (a, b) -> b
snd (FunInfo -> Bool) -> TCMT IO FunInfo -> TCM Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateT ESt TCM FunInfo -> TCMT IO FunInfo
forall a. E a -> TCM a
runE (QName -> StateT ESt TCM FunInfo
getFunInfo QName
qn)

telListView :: Type -> TCM (ListTel, Type)
telListView :: Type -> TCMT IO (ListTel, Type)
telListView Type
t = do
  TelV Tele (Dom Type)
tel Type
t <- Type -> TCMT IO (TelV Type)
forall (m :: * -> *).
(MonadReduce m, MonadAddContext m) =>
Type -> m (TelV Type)
telView Type
t
  (ListTel, Type) -> TCMT IO (ListTel, Type)
forall (m :: * -> *) a. Monad m => a -> m a
return (Tele (Dom Type) -> ListTel
forall t. Tele (Dom t) -> [Dom (String, t)]
telToList Tele (Dom Type)
tel, Type
t)

typeWithoutParams :: QName -> TCM (ListTel, Type)
typeWithoutParams :: QName -> TCMT IO (ListTel, Type)
typeWithoutParams QName
q = do
  Definition
def <- QName -> TCMT IO Definition
forall (m :: * -> *). HasConstInfo m => QName -> m Definition
getConstInfo QName
q
  let d :: Int
d = case Definition -> Defn
I.theDef Definition
def of
        Function{ funProjection :: Defn -> Maybe Projection
funProjection = Just Projection{ projIndex :: Projection -> Int
projIndex = Int
i } } -> Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
        Constructor{ conPars :: Defn -> Int
conPars = Int
n } -> Int
n
        Defn
_                          -> Int
0
  (ListTel -> ListTel) -> (ListTel, Type) -> (ListTel, Type)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (Int -> ListTel -> ListTel
forall a. Int -> [a] -> [a]
drop Int
d) ((ListTel, Type) -> (ListTel, Type))
-> TCMT IO (ListTel, Type) -> TCMT IO (ListTel, Type)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Type -> TCMT IO (ListTel, Type)
telListView (Definition -> Type
defType Definition
def)

getTypeInfo :: Type -> E TypeInfo
getTypeInfo :: Type -> StateT ESt TCM TypeInfo
getTypeInfo Type
t0 = do
  (ListTel
tel, Type
t) <- TCMT IO (ListTel, Type) -> StateT ESt TCM (ListTel, Type)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCMT IO (ListTel, Type) -> StateT ESt TCM (ListTel, Type))
-> TCMT IO (ListTel, Type) -> StateT ESt TCM (ListTel, Type)
forall a b. (a -> b) -> a -> b
$ Type -> TCMT IO (ListTel, Type)
telListView Type
t0
  TypeInfo
et <- case Type -> Term
forall t a. Type'' t a -> a
I.unEl Type
t of
    I.Def QName
d Elims
_ -> do
      -- #2916: Only update the memo table for d. Results for other types are
      -- under the assumption that d is erasable!
      Map QName TypeInfo
oldMap <- Lens' (Map QName TypeInfo) ESt
-> StateT ESt TCM (Map QName TypeInfo)
forall o (m :: * -> *) i. MonadState o m => Lens' i o -> m i
use Lens' (Map QName TypeInfo) ESt
typeMap
      TypeInfo
dInfo <- QName -> StateT ESt TCM TypeInfo
typeInfo QName
d
      Lens' (Map QName TypeInfo) ESt
typeMap Lens' (Map QName TypeInfo) ESt -> Map QName TypeInfo -> E ()
forall o (m :: * -> *) i. MonadState o m => Lens' i o -> i -> m ()
.= QName -> TypeInfo -> Map QName TypeInfo -> Map QName TypeInfo
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert QName
d TypeInfo
dInfo Map QName TypeInfo
oldMap
      TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return TypeInfo
dInfo
    Sort{}    -> TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return TypeInfo
Erasable
    Term
_         -> TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return TypeInfo
NotErasable
  [TypeInfo]
is <- (Dom' Term (String, Type) -> StateT ESt TCM TypeInfo)
-> ListTel -> StateT ESt TCM [TypeInfo]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Type -> StateT ESt TCM TypeInfo
getTypeInfo (Type -> StateT ESt TCM TypeInfo)
-> (Dom' Term (String, Type) -> Type)
-> Dom' Term (String, Type)
-> StateT ESt TCM TypeInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, Type) -> Type
forall a b. (a, b) -> b
snd ((String, Type) -> Type)
-> (Dom' Term (String, Type) -> (String, Type))
-> Dom' Term (String, Type)
-> Type
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dom' Term (String, Type) -> (String, Type)
forall (t :: * -> *) a. Decoration t => t a -> a
dget) ListTel
tel
  let e :: TypeInfo
e | (TypeInfo -> Bool) -> [TypeInfo] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (TypeInfo -> TypeInfo -> Bool
forall a. Eq a => a -> a -> Bool
== TypeInfo
Empty) [TypeInfo]
is = TypeInfo
Erasable
        | [TypeInfo] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [TypeInfo]
is           = TypeInfo
et        -- TODO: guard should really be "all inhabited is"
        | TypeInfo
et TypeInfo -> TypeInfo -> Bool
forall a. Eq a => a -> a -> Bool
== TypeInfo
Empty       = TypeInfo
Erasable
        | Bool
otherwise         = TypeInfo
et
  TCM () -> E ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCM () -> E ()) -> TCM () -> E ()
forall a b. (a -> b) -> a -> b
$ String -> Int -> TCM Doc -> TCM ()
forall (m :: * -> *).
MonadDebug m =>
String -> Int -> TCM Doc -> m ()
reportSDoc String
"treeless.opt.erase.type" Int
50 (TCM Doc -> TCM ()) -> TCM Doc -> TCM ()
forall a b. (a -> b) -> a -> b
$ Type -> TCM Doc
forall a (m :: * -> *). (PrettyTCM a, MonadPretty m) => a -> m Doc
prettyTCM Type
t0 TCM Doc -> TCM Doc -> TCM Doc
forall (m :: * -> *). Applicative m => m Doc -> m Doc -> m Doc
<+> String -> TCM Doc
forall (m :: * -> *). Monad m => String -> m Doc
text (String
"is " String -> ShowS
forall a. [a] -> [a] -> [a]
++ TypeInfo -> String
forall a. Show a => a -> String
show TypeInfo
e)
  TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return TypeInfo
e
  where
  typeInfo :: QName -> E TypeInfo
  typeInfo :: QName -> StateT ESt TCM TypeInfo
typeInfo QName
q = StateT ESt TCM Bool
-> StateT ESt TCM TypeInfo
-> StateT ESt TCM TypeInfo
-> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM (QName -> StateT ESt TCM Bool
erasureForbidden QName
q) (TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return TypeInfo
NotErasable) (StateT ESt TCM TypeInfo -> StateT ESt TCM TypeInfo)
-> StateT ESt TCM TypeInfo -> StateT ESt TCM TypeInfo
forall a b. (a -> b) -> a -> b
$ {-else-} do
    Lens' (Maybe TypeInfo) ESt
-> TypeInfo -> StateT ESt TCM TypeInfo -> StateT ESt TCM TypeInfo
forall s (m :: * -> *) a.
MonadState s m =>
Lens' (Maybe a) s -> a -> m a -> m a
memoRec ((Map QName TypeInfo -> f (Map QName TypeInfo)) -> ESt -> f ESt
Lens' (Map QName TypeInfo) ESt
typeMap ((Map QName TypeInfo -> f (Map QName TypeInfo)) -> ESt -> f ESt)
-> ((Maybe TypeInfo -> f (Maybe TypeInfo))
    -> Map QName TypeInfo -> f (Map QName TypeInfo))
-> (Maybe TypeInfo -> f (Maybe TypeInfo))
-> ESt
-> f ESt
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QName -> Lens' (Maybe TypeInfo) (Map QName TypeInfo)
forall k v. Ord k => k -> Lens' (Maybe v) (Map k v)
key QName
q) TypeInfo
Erasable (StateT ESt TCM TypeInfo -> StateT ESt TCM TypeInfo)
-> StateT ESt TCM TypeInfo -> StateT ESt TCM TypeInfo
forall a b. (a -> b) -> a -> b
$ do  -- assume recursive occurrences are erasable
      [Maybe QName]
msizes <- TCMT IO [Maybe QName] -> StateT ESt TCM [Maybe QName]
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCMT IO [Maybe QName] -> StateT ESt TCM [Maybe QName])
-> TCMT IO [Maybe QName] -> StateT ESt TCM [Maybe QName]
forall a b. (a -> b) -> a -> b
$ (String -> TCMT IO (Maybe QName))
-> [String] -> TCMT IO [Maybe QName]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> TCMT IO (Maybe QName)
getBuiltinName
                         [String
builtinSize, String
builtinSizeLt]
      Definition
def    <- TCMT IO Definition -> StateT ESt TCM Definition
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCMT IO Definition -> StateT ESt TCM Definition)
-> TCMT IO Definition -> StateT ESt TCM Definition
forall a b. (a -> b) -> a -> b
$ QName -> TCMT IO Definition
forall (m :: * -> *). HasConstInfo m => QName -> m Definition
getConstInfo QName
q
      Maybe [QName]
mcs    <- Maybe [QName] -> StateT ESt TCM (Maybe [QName])
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe [QName] -> StateT ESt TCM (Maybe [QName]))
-> Maybe [QName] -> StateT ESt TCM (Maybe [QName])
forall a b. (a -> b) -> a -> b
$ case Definition -> Defn
I.theDef Definition
def of
        I.Datatype{ dataCons :: Defn -> [QName]
dataCons = [QName]
cs } -> [QName] -> Maybe [QName]
forall a. a -> Maybe a
Just [QName]
cs
        I.Record{ recConHead :: Defn -> ConHead
recConHead = ConHead
c }  -> [QName] -> Maybe [QName]
forall a. a -> Maybe a
Just [ConHead -> QName
conName ConHead
c]
        Defn
_                           -> Maybe [QName]
forall a. Maybe a
Nothing
      case Maybe [QName]
mcs of
        Maybe [QName]
_ | QName -> Maybe QName
forall a. a -> Maybe a
Just QName
q Maybe QName -> [Maybe QName] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Maybe QName]
msizes -> TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return TypeInfo
Erasable
        Just [QName
c] -> do
          (ListTel
ts, Type
_) <- TCMT IO (ListTel, Type) -> StateT ESt TCM (ListTel, Type)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCMT IO (ListTel, Type) -> StateT ESt TCM (ListTel, Type))
-> TCMT IO (ListTel, Type) -> StateT ESt TCM (ListTel, Type)
forall a b. (a -> b) -> a -> b
$ QName -> TCMT IO (ListTel, Type)
typeWithoutParams QName
c
          let rs :: [Modality]
rs = (Dom' Term (String, Type) -> Modality) -> ListTel -> [Modality]
forall a b. (a -> b) -> [a] -> [b]
map Dom' Term (String, Type) -> Modality
forall a. LensModality a => a -> Modality
getModality ListTel
ts
          [TypeInfo]
is <- (Dom' Term (String, Type) -> StateT ESt TCM TypeInfo)
-> ListTel -> StateT ESt TCM [TypeInfo]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Type -> StateT ESt TCM TypeInfo
getTypeInfo (Type -> StateT ESt TCM TypeInfo)
-> (Dom' Term (String, Type) -> Type)
-> Dom' Term (String, Type)
-> StateT ESt TCM TypeInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, Type) -> Type
forall a b. (a, b) -> b
snd ((String, Type) -> Type)
-> (Dom' Term (String, Type) -> (String, Type))
-> Dom' Term (String, Type)
-> Type
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dom' Term (String, Type) -> (String, Type)
forall (t :: * -> *) a. Decoration t => t a -> a
dget) ListTel
ts
          let er :: Bool
er = [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and [ TypeInfo -> Bool
erasable TypeInfo
i Bool -> Bool -> Bool
|| Bool -> Bool
not (Modality -> Bool
forall a. LensModality a => a -> Bool
usableModality Modality
r) | (TypeInfo
i, Modality
r) <- [TypeInfo] -> [Modality] -> [(TypeInfo, Modality)]
forall a b. [a] -> [b] -> [(a, b)]
zip [TypeInfo]
is [Modality]
rs ]
          TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return (TypeInfo -> StateT ESt TCM TypeInfo)
-> TypeInfo -> StateT ESt TCM TypeInfo
forall a b. (a -> b) -> a -> b
$ if Bool
er then TypeInfo
Erasable else TypeInfo
NotErasable
        Just []      -> TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return TypeInfo
Empty
        Just (QName
_:QName
_:[QName]
_) -> TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return TypeInfo
NotErasable
        Maybe [QName]
Nothing ->
          case Definition -> Defn
I.theDef Definition
def of
            I.Function{ funClauses :: Defn -> [Clause]
funClauses = [Clause]
cs } ->
              [TypeInfo] -> TypeInfo
sumTypeInfo ([TypeInfo] -> TypeInfo)
-> StateT ESt TCM [TypeInfo] -> StateT ESt TCM TypeInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Clause -> StateT ESt TCM TypeInfo)
-> [Clause] -> StateT ESt TCM [TypeInfo]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (StateT ESt TCM TypeInfo
-> (Term -> StateT ESt TCM TypeInfo)
-> Maybe Term
-> StateT ESt TCM TypeInfo
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return TypeInfo
Empty) (Type -> StateT ESt TCM TypeInfo
getTypeInfo (Type -> StateT ESt TCM TypeInfo)
-> (Term -> Type) -> Term -> StateT ESt TCM TypeInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Sort' Term -> Term -> Type
forall t a. Sort' t -> a -> Type'' t a
El Sort' Term
HasCallStack => Sort' Term
__DUMMY_SORT__) (Maybe Term -> StateT ESt TCM TypeInfo)
-> (Clause -> Maybe Term) -> Clause -> StateT ESt TCM TypeInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Clause -> Maybe Term
clauseBody) [Clause]
cs
            Defn
_ -> TypeInfo -> StateT ESt TCM TypeInfo
forall (m :: * -> *) a. Monad m => a -> m a
return TypeInfo
NotErasable
  -- | The backend also has a say whether a type is eraseable or not.
  erasureForbidden :: QName -> E Bool
  erasureForbidden :: QName -> StateT ESt TCM Bool
erasureForbidden QName
q = TCM Bool -> StateT ESt TCM Bool
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TCM Bool -> StateT ESt TCM Bool)
-> TCM Bool -> StateT ESt TCM Bool
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not (Bool -> Bool) -> TCM Bool -> TCM Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> QName -> TCM Bool
activeBackendMayEraseType QName
q