tree of (trace, access path) associations organized by structure of access paths

`module TraceDomain : AbstractDomain.WithBottom`
`module AccessMap : InferStdlib.PrettyPrintable.PPMap with type PPMap.key = InferIR.AccessPath.access`
`module BaseMap = InferIR.AccessPath.BaseMap`
`type node``= TraceDomain.astate * tree```
`type tree````=`

`|` `Subtree of node AccessMap.t` | (** map from access -> nodes. a leaf is encoded as an empty map *)
`|` `Star` | (** special leaf for starred access paths *)

``
`type t``= node BaseMap.t```

map from base var -> access subtree. Here's how to represent a few different kinds of trace * access path associations:

          (x, T)               := { x |-> (T, Subtree {}) }
          (x.f, T)             := { x |-> (empty, Subtree { f |-> (T, Subtree {}) }) }
          (x*, T)              := { x |-> (T, Star) }
          (x.f*, T)            := { x |-> (empty, Subtree { f |-> (T, Star) }) }
          (x, T1), (y, T2)     := { x |-> (T1, Subtree {}), y |-> (T2, Subtree {}) }
          (x.f, T1), (x.g, T2) := { x |-> (empty, Subtree { f |-> (T1, Subtree {}),
                                                            g |-> (T2, Subtree {}) }) }

`include AbstractDomain.WithBottom with type astate = t`
`include AbstractDomain.S`
`type astate`````
`val (<=) : lhs:astate ‑> rhs:astate ‑> bool`

the partial order induced by join

`val join : astate ‑> astate ‑> astate`
`val widen : prev:astate ‑> next:astate ‑> num_iters:int ‑> astate`
`val pp : InferModules.AbstractDomain.F.formatter ‑> astate ‑> unit`
`val empty : astate`

The bottom value of the domain. Naming it empty instead of bottom helps to bind the empty value for sets and maps to the natural definition for bottom

`val is_empty : astate ‑> bool`

Return true if this is the bottom value

`val empty_node : node`
`val make_node : TraceDomain.astate ‑> node AccessMap.t ‑> node`
`val make_access_node : TraceDomain.astate ‑> InferIR.AccessPath.access ‑> TraceDomain.astate ‑> node`

for testing only

`val make_normal_leaf : TraceDomain.astate ‑> node`

create a leaf node with no successors

`val make_starred_leaf : TraceDomain.astate ‑> node`

create a leaf node with a wildcard successor

`val get_node : InferIR.AccessPath.Abs.t ‑> t ‑> node option`

retrieve the node associated with the given access path

`val get_trace : InferIR.AccessPath.Abs.t ‑> t ‑> TraceDomain.astate option`

retrieve the trace associated with the given access path

`val add_node : InferIR.AccessPath.Abs.t ‑> node ‑> t ‑> t`

add the given access path to the tree and associate its last access with with the given node. if any of the accesses in the path are not already present in the tree, they will be added with with empty traces associated with each of the inner nodes.

`val add_trace : InferIR.AccessPath.Abs.t ‑> TraceDomain.astate ‑> t ‑> t`

add the given access path to the tree and associate its last access with with the given trace. if any of the accesses in the path are not already present in the tree, they will be added with with empty traces associated with each of the inner nodes.

`val node_join : node ‑> node ‑> node`

join two nodes

`val fold : ('a ‑> InferIR.AccessPath.Abs.t ‑> node ‑> 'a) ‑> t ‑> 'a ‑> 'a`

apply a function to each (access path, node) pair in the tree.

`val trace_fold : ('a ‑> InferIR.AccessPath.Abs.t ‑> TraceDomain.astate ‑> 'a) ‑> t ‑> 'a ‑> 'a`
`val exists : (InferIR.AccessPath.Abs.t ‑> node ‑> bool) ‑> t ‑> bool`
`val iter : (InferIR.AccessPath.Abs.t ‑> node ‑> unit) ‑> t ‑> unit`
`val depth : t ‑> int`

number of traces in the tallest branch of the tree

`val pp_node : Format.formatter ‑> node ‑> unit`