Agda
Safe HaskellNone
LanguageHaskell2010

Agda.TypeChecking.Positivity.OccurrenceAnalysis

Description

Computing the occurrence graph for a mutual block. This is used to compute polarities of arguments and to check positivity.

  • We do a traversal over internal syntax.
  • The occurrence graph is 'NodeMap (NodeMap Edge)', where NodeMap is a mutable hashtable keyed by graph nodes. The outer keys are sources and the inner keys are targets. We insert edges into the graph during the traversal.
  • An edge from source to target means that source occurs in target.
  • A graph node is either 'DefNode QName', which is a definition site of a mutual name, or 'ArgNode QName Int', which is an argument of a mutual name, indexed left-right starting from 0.
  • An edge contains an Occurrence, the Range of the actual occurrence in the internal syntax and an OccursPath that can be used to produce a textual warning message.

The occurrence graph is imprecise in several ways.

  • We only normalize types of data constructors and don't compute anything else.
  • We have at most a single edge between two nodes. We aggregate multiple actual occurrences into a single edge, using mergeEdges.

Lastly, applications of mutual names to arguments is handled in a rather imprecise way. See Issue 1984 for illustration:

mutual
  record Fun (A : Set) (B : A → Set) : Set where
    field fun : (x : A) → B x

  data U : Set where
    Π : (A : U) (B : El A → U) → U

  El : U → Set
  El (Π A B) = Fun (El A) (λ x → El (B x))

In this case:

  • Fun occurs in El.
  • El A occurs in the first argument of Fun.
  • The first argument of Fun occurs in Fun.

In short, when we apply a mutual name to an argument, we view that as if the argument was substituted inside the body of the mutual name definition.

Hence, Fun "occurs" in Fun, and it does so negatively. This is kinda bogus, because Fun could be moved outside of the mutual block.

A potential fix of this issue would be to first split the mutual block into strongly connected components based on only QName occurrences, and afterwards do the current occurrence analysis for each sub-block.

Immutable representation

Instead of using the mutable hashtable, we use immutable "generic" graphs from Unidirectional for printing warnings and debug messages, and also to define tests in internal property tests. One reason is convenience. Another reason is that the previous (less optimized) implementation before PR 8411 used the generic graphs, and we just reuse the old implementation for printing. See toGenericGraph and fromGenericGraph.

Synopsis

Documentation

data Node Source #

Instances

Instances details
Pretty Node Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.Occurrence

PrettyTCM Node Source # 
Instance details

Defined in Agda.TypeChecking.Positivity

Methods

prettyTCM :: MonadPretty m => Node -> m Doc Source #

Eq Node Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.Occurrence

Methods

(==) :: Node -> Node -> Bool #

(/=) :: Node -> Node -> Bool #

Ord Node Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.Occurrence

Methods

compare :: Node -> Node -> Ordering #

(<) :: Node -> Node -> Bool #

(<=) :: Node -> Node -> Bool #

(>) :: Node -> Node -> Bool #

(>=) :: Node -> Node -> Bool #

max :: Node -> Node -> Node #

min :: Node -> Node -> Node #

Show Node Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.Occurrence

Methods

showsPrec :: Int -> Node -> ShowS #

show :: Node -> String #

showList :: [Node] -> ShowS #

Hashable Node Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.Occurrence

Methods

hashWithSalt :: Int -> Node -> Int #

hash :: Node -> Int #

pattern DefNode :: QName -> Node Source #

Definition site of a mutual definition

pattern ArgNode :: QName -> Int -> Node Source #

Occurrence of the nth definition argument inside the definition.

data Edge a Source #

Constructors

Edge !Occurrence !a 

Instances

Instances details
Functor Edge Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.Occurrence

Methods

fmap :: (a -> b) -> Edge a -> Edge b #

(<$) :: a -> Edge b -> Edge a #

PrettyTCMWithNode (Edge OccursWhere) Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.OccurrenceAnalysis

Pretty a => PrettyTCMWithNode (Edge a) Source # 
Instance details

Defined in Agda.TypeChecking.Positivity

Monoid a => SemiRing (Edge a) Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.Occurrence

Methods

ozero :: Edge a Source #

oone :: Edge a Source #

oplus :: Edge a -> Edge a -> Edge a Source #

otimes :: Edge a -> Edge a -> Edge a Source #

Eq a => Eq (Edge a) Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.Occurrence

Methods

(==) :: Edge a -> Edge a -> Bool #

(/=) :: Edge a -> Edge a -> Bool #

Ord a => Ord (Edge a) Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.Occurrence

Methods

compare :: Edge a -> Edge a -> Ordering #

(<) :: Edge a -> Edge a -> Bool #

(<=) :: Edge a -> Edge a -> Bool #

(>) :: Edge a -> Edge a -> Bool #

(>=) :: Edge a -> Edge a -> Bool #

max :: Edge a -> Edge a -> Edge a #

min :: Edge a -> Edge a -> Edge a #

Show a => Show (Edge a) Source # 
Instance details

Defined in Agda.TypeChecking.Positivity.Occurrence

Methods

showsPrec :: Int -> Edge a -> ShowS #

show :: Edge a -> String #

showList :: [Edge a] -> ShowS #

type OccGraph = NodeMap (NodeMap (Edge OccursWhere)) Source #

Meaning of the graph: the keys in the outer NodeMap occur in the keys of the inner NodeMap.

stronglyConnComp :: OccGraph -> IO [SCC Node] Source #

Strongly connected components, in reverse topological order.

transitiveOccurrence :: OccGraph -> Node -> Node -> IO Occurrence Source #

Search for transitive occurrences through the occurrence graph. We compute the oplus sum of all paths from the source to the target. This is not as bad as it sounds, becuse a) we can short-circuit a search when a Mixed path is found b) only 4 possible Occurrences remain, (discounting Mixed and Unused) and we can use a DFS where each node is visited at most 4 times, for each Occurence of the path to the node from the source.

lookupNode :: Node -> NodeMap v -> (v -> IO a) -> IO a -> IO a Source #

Getting the "found" and "not found" branches as arguments. We do this to fuse away the Maybe in the lookup result.

toGenericGraph :: OccGraph -> Graph Node (Edge OccursWhere) Source #

Convert to generic Utils graph, for the purpose of testing and warning rendering.

fromGenericGraph :: Graph Node (Edge a) -> OccGraph Source #

Make a graph from a generic one. We use this in testing in Internal.TypeChecking.Positivity where it's much more convenient to generate immutable graphs. Note: we ignore occurrence location info.

Orphan instances

Exception Occurrence Source #

Exception for short-circuiting when finding a Mixed path from source to target.

Instance details

PrettyTCMWithNode (Edge OccursWhere) Source # 
Instance details