{-# LANGUAGE NondecreasingIndentation #-}
module Agda.TypeChecking.Opacity
( saturateOpaqueBlocks
, isAccessibleDef
, hasAccessibleDef
)
where
import Control.Monad.State
import Control.Exception
import Control.DeepSeq
import Control.Monad
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Map.Strict as Map
import qualified Data.HashSet as HashSet
import qualified Data.List as List
import Data.HashMap.Strict (HashMap)
import Data.HashSet (HashSet)
import Data.Map.Strict (Map)
import Data.Foldable
import Data.Maybe
import qualified Agda.Syntax.Abstract as A
import Agda.Syntax.Internal
import Agda.Syntax.Position
import Agda.Syntax.Common
import Agda.TypeChecking.Warnings
import Agda.TypeChecking.Pretty
import Agda.TypeChecking.Monad
import Agda.Utils.Impossible
import Agda.Utils.Lens
import Agda.Utils.List
import Agda.Utils.Monad
saturateOpaqueBlocks
:: forall m. (MonadTCState m, MonadFresh OpaqueId m, MonadTrace m, MonadWarning m, MonadIO m)
=> m ()
saturateOpaqueBlocks :: forall (m :: * -> *).
(MonadTCState m, MonadFresh OpaqueId m, MonadTrace m,
MonadWarning m, MonadIO m) =>
m ()
saturateOpaqueBlocks = m ()
entry where
entry :: m ()
entry = do
known <- Lens' TCState (Map OpaqueId OpaqueBlock)
-> m (Map OpaqueId OpaqueBlock)
forall (m :: * -> *) a. ReadTCState m => Lens' TCState a -> m a
useTC (Map OpaqueId OpaqueBlock -> f (Map OpaqueId OpaqueBlock))
-> TCState -> f TCState
Lens' TCState (Map OpaqueId OpaqueBlock)
stOpaqueBlocks
inverse <- useTC stOpaqueIds
OpaqueId _ ourmod <- fresh
canonical <- useTC stCopiedNames
backcopies <- useTC stNameCopies
reportSDoc "tc.opaque.copy" 45 $ "Canonical names of copied definitions:" $+$ pretty (HashMap.toList canonical)
reportSDoc "tc.opaque.copy" 45 $ "Backcopies:" $+$ pretty (HashMap.toList (toList <$> backcopies))
let
isOurs (OpaqueId Word64
_ ModuleNameHash
mod, OpaqueBlock
_) = ModuleNameHash
mod ModuleNameHash -> ModuleNameHash -> Bool
forall a. Eq a => a -> a -> Bool
== ModuleNameHash
ourmod
canonise QName
name = QName -> Maybe QName -> QName
forall a. a -> Maybe a -> a
fromMaybe QName
name (QName -> HashMap QName QName -> Maybe QName
forall k v. Hashable k => k -> HashMap k v -> Maybe v
HashMap.lookup QName
name HashMap QName QName
canonical)
ours = (OpaqueId, OpaqueBlock) -> OpaqueBlock
forall a b. (a, b) -> b
snd ((OpaqueId, OpaqueBlock) -> OpaqueBlock)
-> [(OpaqueId, OpaqueBlock)] -> [OpaqueBlock]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((OpaqueId, OpaqueBlock) -> Bool)
-> [(OpaqueId, OpaqueBlock)] -> [(OpaqueId, OpaqueBlock)]
forall a. (a -> Bool) -> [a] -> [a]
filter (OpaqueId, OpaqueBlock) -> Bool
isOurs (Map OpaqueId OpaqueBlock -> [(OpaqueId, OpaqueBlock)]
forall k a. Map k a -> [(k, a)]
Map.toAscList Map OpaqueId OpaqueBlock
known)
() <- liftIO $ evaluate (rnf (canonical, backcopies))
reportSDoc "tc.opaque" 30 $ vcat $
text "Opaque blocks defined in this module:":map pretty ours
(blocks, names) <- computeClosure canonise known inverse ours
let names' = ((QName, HashSet QName)
-> Map QName OpaqueId -> Map QName OpaqueId)
-> Map QName OpaqueId
-> [(QName, HashSet QName)]
-> Map QName OpaqueId
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (QName, HashSet QName) -> Map QName OpaqueId -> Map QName OpaqueId
addBackcopy Map QName OpaqueId
names (HashMap QName (HashSet QName) -> [(QName, HashSet QName)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap QName (HashSet QName)
backcopies)
reportSDoc "tc.opaque.sat" 30 $ vcat $
text "Saturated local opaque blocks":[ pretty block | b@(_,block) <- Map.toList blocks, isOurs b ]
reportSDoc "tc.opaque.sat.full" 50 $ text "Saturated opaque blocks:" $+$ pretty blocks
modifyTC' (set stOpaqueBlocks blocks . set stOpaqueIds names')
computeClosure
:: (QName -> QName)
-> Map OpaqueId OpaqueBlock
-> Map QName OpaqueId
-> [OpaqueBlock]
-> m ( Map OpaqueId OpaqueBlock
, Map QName OpaqueId
)
computeClosure :: (QName -> QName)
-> Map OpaqueId OpaqueBlock
-> Map QName OpaqueId
-> [OpaqueBlock]
-> m (Map OpaqueId OpaqueBlock, Map QName OpaqueId)
computeClosure QName -> QName
canonise !Map OpaqueId OpaqueBlock
blocks !Map QName OpaqueId
names [] = (Map OpaqueId OpaqueBlock, Map QName OpaqueId)
-> m (Map OpaqueId OpaqueBlock, Map QName OpaqueId)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Map OpaqueId OpaqueBlock
blocks, Map QName OpaqueId
names)
computeClosure QName -> QName
canonise Map OpaqueId OpaqueBlock
blocks Map QName OpaqueId
names (OpaqueBlock
block:[OpaqueBlock]
xs) = Range' SrcFile
-> m (Map OpaqueId OpaqueBlock, Map QName OpaqueId)
-> m (Map OpaqueId OpaqueBlock, Map QName OpaqueId)
forall (m :: * -> *) x a.
(MonadTrace m, HasRange x) =>
x -> m a -> m a
setCurrentRange (OpaqueBlock -> Range' SrcFile
opaqueRange OpaqueBlock
block) (m (Map OpaqueId OpaqueBlock, Map QName OpaqueId)
-> m (Map OpaqueId OpaqueBlock, Map QName OpaqueId))
-> m (Map OpaqueId OpaqueBlock, Map QName OpaqueId)
-> m (Map OpaqueId OpaqueBlock, Map QName OpaqueId)
forall a b. (a -> b) -> a -> b
$ do
let
yell :: QName -> a -> m a
yell QName
nm a
accum = Range' SrcFile -> m a -> m a
forall (m :: * -> *) x a.
(MonadTrace m, HasRange x) =>
x -> m a -> m a
setCurrentRange (QName -> Range' SrcFile
forall a. HasRange a => a -> Range' SrcFile
getRange QName
nm) (m a -> m a) -> m a -> m a
forall a b. (a -> b) -> a -> b
$ do
Warning -> m ()
forall (m :: * -> *).
(HasCallStack, MonadWarning m) =>
Warning -> m ()
warning (QName -> Warning
UnfoldTransparentName QName
nm)
a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
accum
transitive :: QName -> HashSet QName -> m (HashSet QName)
transitive QName
prenom HashSet QName
accum = m (HashSet QName) -> Maybe (m (HashSet QName)) -> m (HashSet QName)
forall a. a -> Maybe a -> a
fromMaybe (QName -> HashSet QName -> m (HashSet QName)
forall {m :: * -> *} {a}.
(MonadTrace m, MonadWarning m) =>
QName -> a -> m a
yell QName
prenom HashSet QName
accum) (Maybe (m (HashSet QName)) -> m (HashSet QName))
-> Maybe (m (HashSet QName)) -> m (HashSet QName)
forall a b. (a -> b) -> a -> b
$ do
let nm :: QName
nm = QName -> QName
canonise QName
prenom
id <- QName -> Map QName OpaqueId -> Maybe OpaqueId
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup QName
nm Map QName OpaqueId
names
block <- Map.lookup id blocks
pure . pure $ HashSet.union (opaqueUnfolding block) accum
VerboseKey -> VerboseLevel -> TCMT IO Doc -> m ()
forall (m :: * -> *).
MonadDebug m =>
VerboseKey -> VerboseLevel -> TCMT IO Doc -> m ()
reportSDoc VerboseKey
"tc.opaque.copy" VerboseLevel
45 (TCMT IO Doc -> m ()) -> TCMT IO Doc -> m ()
forall a b. (a -> b) -> a -> b
$
[TCMT IO Doc] -> TCMT IO Doc
forall (m :: * -> *) (t :: * -> *).
(Applicative m, Foldable t) =>
t (m Doc) -> m Doc
vcat [ TCMT IO Doc
"Stated unfolding clause: " TCMT IO Doc -> TCMT IO Doc -> TCMT IO Doc
forall (m :: * -> *). Applicative m => m Doc -> m Doc -> m Doc
<+> [QName] -> TCMT IO Doc
forall (m :: * -> *) a. (Applicative m, Pretty a) => a -> m Doc
pretty (HashSet QName -> [QName]
forall a. HashSet a -> [a]
HashSet.toList (OpaqueBlock -> HashSet QName
opaqueUnfolding OpaqueBlock
block))
, TCMT IO Doc
"with (sub)canonical names:" TCMT IO Doc -> TCMT IO Doc -> TCMT IO Doc
forall (m :: * -> *). Applicative m => m Doc -> m Doc -> m Doc
<+> [QName] -> TCMT IO Doc
forall (m :: * -> *) a. (Applicative m, Pretty a) => a -> m Doc
pretty (QName -> QName
canonise (QName -> QName) -> [QName] -> [QName]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HashSet QName -> [QName]
forall a. HashSet a -> [a]
HashSet.toList (OpaqueBlock -> HashSet QName
opaqueUnfolding OpaqueBlock
block))
]
closed <- (QName -> HashSet QName -> m (HashSet QName))
-> HashSet QName -> HashSet QName -> m (HashSet QName)
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> b -> m b) -> b -> t a -> m b
foldrM QName -> HashSet QName -> m (HashSet QName)
transitive
( OpaqueBlock -> HashSet QName
opaqueDecls OpaqueBlock
block
HashSet QName -> HashSet QName -> HashSet QName
forall a. Semigroup a => a -> a -> a
<> (OpaqueBlock -> HashSet QName)
-> Maybe OpaqueBlock -> HashSet QName
forall m a. Monoid m => (a -> m) -> Maybe a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap OpaqueBlock -> HashSet QName
opaqueUnfolding (OpaqueBlock -> Maybe OpaqueId
opaqueParent OpaqueBlock
block Maybe OpaqueId
-> (OpaqueId -> Maybe OpaqueBlock) -> Maybe OpaqueBlock
forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (OpaqueId -> Map OpaqueId OpaqueBlock -> Maybe OpaqueBlock)
-> Map OpaqueId OpaqueBlock -> OpaqueId -> Maybe OpaqueBlock
forall a b c. (a -> b -> c) -> b -> a -> c
flip OpaqueId -> Map OpaqueId OpaqueBlock -> Maybe OpaqueBlock
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Map OpaqueId OpaqueBlock
blocks)
)
(OpaqueBlock -> HashSet QName
opaqueUnfolding OpaqueBlock
block)
let
block' = OpaqueBlock
block { opaqueUnfolding = closed }
names' = (QName -> Map QName OpaqueId -> Map QName OpaqueId)
-> Map QName OpaqueId -> HashSet QName -> Map QName OpaqueId
forall b a. (b -> a -> a) -> a -> HashSet b -> a
HashSet.foldr (\QName
name -> QName -> OpaqueId -> Map QName OpaqueId -> Map QName OpaqueId
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert QName
name (OpaqueBlock -> OpaqueId
opaqueId OpaqueBlock
block)) Map QName OpaqueId
names
(OpaqueBlock -> HashSet QName
opaqueDecls OpaqueBlock
block)
computeClosure canonise (Map.insert (opaqueId block) block' blocks) names' xs
addBackcopy :: (QName, HashSet QName) -> Map QName OpaqueId -> Map QName OpaqueId
addBackcopy :: (QName, HashSet QName) -> Map QName OpaqueId -> Map QName OpaqueId
addBackcopy (QName
from, HashSet QName
prop) Map QName OpaqueId
map
| Just OpaqueId
id <- QName -> Map QName OpaqueId -> Maybe OpaqueId
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup QName
from Map QName OpaqueId
map = (QName -> Map QName OpaqueId -> Map QName OpaqueId)
-> Map QName OpaqueId -> HashSet QName -> Map QName OpaqueId
forall b a. (b -> a -> a) -> a -> HashSet b -> a
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ((QName -> OpaqueId -> Map QName OpaqueId -> Map QName OpaqueId)
-> OpaqueId -> QName -> Map QName OpaqueId -> Map QName OpaqueId
forall a b c. (a -> b -> c) -> b -> a -> c
flip QName -> OpaqueId -> Map QName OpaqueId -> Map QName OpaqueId
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert OpaqueId
id) Map QName OpaqueId
map HashSet QName
prop
| Bool
otherwise = Map QName OpaqueId
map
isAccessibleDef :: TCEnv -> TCState -> Definition -> Bool
isAccessibleDef :: TCEnv -> TCState -> Definition -> Bool
isAccessibleDef TCEnv
env TCState
state Definition
defn
| (TCEnv
env TCEnv -> Getting AbstractMode TCEnv AbstractMode -> AbstractMode
forall s a. s -> Getting a s a -> a
^. Getting AbstractMode TCEnv AbstractMode
Lens' TCEnv AbstractMode
eAbstractMode) AbstractMode -> AbstractMode -> Bool
forall a. Eq a => a -> a -> Bool
== AbstractMode
IgnoreAbstractMode = Bool
True
isAccessibleDef TCEnv
env TCState
state Definition
defn =
let
concretise :: IsAbstract -> IsAbstract
concretise IsAbstract
def = case TCEnv
env TCEnv -> Getting AbstractMode TCEnv AbstractMode -> AbstractMode
forall s a. s -> Getting a s a -> a
^. Getting AbstractMode TCEnv AbstractMode
Lens' TCEnv AbstractMode
eAbstractMode of
AbstractMode
ConcreteMode -> IsAbstract
def
AbstractMode
IgnoreAbstractMode -> IsAbstract
ConcreteDef
AbstractMode
AbstractMode -> let
dropLastModule :: ModuleName -> ModuleName
dropLastModule (MName [Name]
ms) = [Name] -> ModuleName
MName ([Name] -> ModuleName) -> [Name] -> ModuleName
forall a b. (a -> b) -> a -> b
$ [Name] -> [Name] -> [Name]
forall a. [a] -> [a] -> [a]
initWithDefault [Name]
forall a. HasCallStack => a
__IMPOSSIBLE__ [Name]
ms
dropAnon :: ModuleName -> ModuleName
dropAnon (MName [Name]
ms) = [Name] -> ModuleName
MName ([Name] -> ModuleName) -> [Name] -> ModuleName
forall a b. (a -> b) -> a -> b
$ (Name -> Bool) -> [Name] -> [Name]
forall a. (a -> Bool) -> [a] -> [a]
List.dropWhileEnd Name -> Bool
forall a. IsNoName a => a -> Bool
isNoName [Name]
ms
current :: ModuleName
current = ModuleName -> ModuleName
dropAnon (ModuleName -> ModuleName) -> ModuleName -> ModuleName
forall a b. (a -> b) -> a -> b
$ TCEnv
env TCEnv -> Getting ModuleName TCEnv ModuleName -> ModuleName
forall s a. s -> Getting a s a -> a
^. Getting ModuleName TCEnv ModuleName
Lens' TCEnv ModuleName
eCurrentModule
modname :: ModuleName
modname = case Definition -> Defn
theDef Definition
defn of
Constructor{} -> ModuleName -> ModuleName
dropAnon (ModuleName -> ModuleName) -> ModuleName -> ModuleName
forall a b. (a -> b) -> a -> b
$ ModuleName -> ModuleName
dropLastModule (ModuleName -> ModuleName) -> ModuleName -> ModuleName
forall a b. (a -> b) -> a -> b
$ QName -> ModuleName
qnameModule (QName -> ModuleName) -> QName -> ModuleName
forall a b. (a -> b) -> a -> b
$ Definition -> QName
defName Definition
defn
Defn
_ -> ModuleName -> ModuleName
dropAnon (ModuleName -> ModuleName) -> ModuleName -> ModuleName
forall a b. (a -> b) -> a -> b
$ QName -> ModuleName
qnameModule (QName -> ModuleName) -> QName -> ModuleName
forall a b. (a -> b) -> a -> b
$ Definition -> QName
defName Definition
defn
in if ModuleName
current ModuleName -> ModuleName -> Bool
`isLeChildModuleOf` ModuleName
modname
then IsAbstract
ConcreteDef
else IsAbstract
def
clarify :: IsOpaque -> IsOpaque
clarify IsOpaque
def = case TCEnv
env TCEnv
-> Getting (Maybe OpaqueId) TCEnv (Maybe OpaqueId)
-> Maybe OpaqueId
forall s a. s -> Getting a s a -> a
^. Getting (Maybe OpaqueId) TCEnv (Maybe OpaqueId)
Lens' TCEnv (Maybe OpaqueId)
eCurrentOpaqueId of
Just OpaqueId
oid ->
let
block :: OpaqueBlock
block = OpaqueBlock -> Maybe OpaqueBlock -> OpaqueBlock
forall a. a -> Maybe a -> a
fromMaybe OpaqueBlock
forall a. HasCallStack => a
__IMPOSSIBLE__ (Maybe OpaqueBlock -> OpaqueBlock)
-> Maybe OpaqueBlock -> OpaqueBlock
forall a b. (a -> b) -> a -> b
$ OpaqueId -> Map OpaqueId OpaqueBlock -> Maybe OpaqueBlock
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup OpaqueId
oid (Getting
(Map OpaqueId OpaqueBlock) TCState (Map OpaqueId OpaqueBlock)
-> TCState -> Map OpaqueId OpaqueBlock
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting
(Map OpaqueId OpaqueBlock) TCState (Map OpaqueId OpaqueBlock)
Lens' TCState (Map OpaqueId OpaqueBlock)
stOpaqueBlocks TCState
state)
okay :: Bool
okay = Definition -> QName
defName Definition
defn QName -> HashSet QName -> Bool
forall a. Hashable a => a -> HashSet a -> Bool
`HashSet.member` OpaqueBlock -> HashSet QName
opaqueUnfolding OpaqueBlock
block
in if Bool
okay then IsOpaque
TransparentDef else IsOpaque
def
Maybe OpaqueId
Nothing -> IsOpaque
def
plainDef :: Bool
plainDef = Definition -> IsAbstract
defAbstract Definition
defn IsAbstract -> IsAbstract -> Bool
forall a. Eq a => a -> a -> Bool
== IsAbstract
ConcreteDef
Bool -> Bool -> Bool
&& Definition -> IsOpaque
defOpaque Definition
defn IsOpaque -> IsOpaque -> Bool
forall a. Eq a => a -> a -> Bool
== IsOpaque
TransparentDef
in Bool
plainDef
Bool -> Bool -> Bool
|| ( IsAbstract -> IsAbstract
concretise (Definition -> IsAbstract
defAbstract Definition
defn) IsAbstract -> IsAbstract -> Bool
forall a. Eq a => a -> a -> Bool
== IsAbstract
ConcreteDef
Bool -> Bool -> Bool
&& IsOpaque -> IsOpaque
clarify (Definition -> IsOpaque
defOpaque Definition
defn) IsOpaque -> IsOpaque -> Bool
forall a. Eq a => a -> a -> Bool
== IsOpaque
TransparentDef)
hasAccessibleDef
:: (ReadTCState m, HasConstInfo m) => QName -> m Bool
hasAccessibleDef :: forall (m :: * -> *).
(ReadTCState m, HasConstInfo m) =>
QName -> m Bool
hasAccessibleDef QName
qn = do
env <- m TCEnv
forall (m :: * -> *). MonadTCEnv m => m TCEnv
askTC
st <- getTCState
ignoreAbstractMode $ do
def <- getConstInfo qn
pure $ isAccessibleDef env st def