| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Agda.TypeChecking.Positivity.OccurrenceAnalysis
Contents
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
NodeMapis 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, theRangeof the actual occurrence in the internal syntax and anOccursPaththat 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:
Funoccurs inEl.El Aoccurs in the first argument ofFun.- The first argument of
Funoccurs inFun.
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
- data Node
- pattern DefNode :: QName -> Node
- pattern ArgNode :: QName -> Int -> Node
- data Edge a = Edge !Occurrence !a
- type OccGraph = NodeMap (NodeMap (Edge OccursWhere))
- buildOccurrenceGraph :: [QName] -> TCM (OccGraph, Mutuals)
- stronglyConnComp :: OccGraph -> IO [SCC Node]
- transitiveOccurrence :: OccGraph -> Node -> Node -> IO Occurrence
- adjacencyList :: OccGraph -> IO [(Node, Node, Edge OccursWhere)]
- lookupNode :: Node -> NodeMap v -> (v -> IO a) -> IO a -> IO a
- toGenericGraph :: OccGraph -> Graph Node (Edge OccursWhere)
- fromGenericGraph :: Graph Node (Edge a) -> OccGraph
Documentation
pattern ArgNode :: QName -> Int -> Node Source #
Occurrence of the nth definition argument inside the definition.
Constructors
| Edge !Occurrence !a |
Instances
| Functor Edge Source # | |
| PrettyTCMWithNode (Edge OccursWhere) Source # | |
Defined in Agda.TypeChecking.Positivity.OccurrenceAnalysis Methods prettyTCMWithNode :: (PrettyTCM n, MonadPretty m) => WithNode n (Edge OccursWhere) -> m Doc Source # | |
| Pretty a => PrettyTCMWithNode (Edge a) Source # | |
Defined in Agda.TypeChecking.Positivity Methods prettyTCMWithNode :: (PrettyTCM n, MonadPretty m) => WithNode n (Edge a) -> m Doc Source # | |
| Monoid a => SemiRing (Edge a) Source # | |
| Eq a => Eq (Edge a) Source # | |
| Ord a => Ord (Edge a) Source # | |
Defined in Agda.TypeChecking.Positivity.Occurrence | |
| Show a => Show (Edge a) Source # | |
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.
adjacencyList :: OccGraph -> IO [(Node, Node, Edge OccursWhere)] 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. |
Methods toException :: Occurrence -> SomeException # fromException :: SomeException -> Maybe Occurrence # displayException :: Occurrence -> String # backtraceDesired :: Occurrence -> Bool # | |
| PrettyTCMWithNode (Edge OccursWhere) Source # | |
Methods prettyTCMWithNode :: (PrettyTCM n, MonadPretty m) => WithNode n (Edge OccursWhere) -> m Doc Source # | |