The construct graph organizes the constraints by their end-points.
It can be used to view a `R1: R2`

constraint as either an edge `R1 -> R2`

or `R2 -> R1`

depending on the direction type `D`

.

In normal mode, a `R1: R2`

constraint results in an edge `R1 -> R2`

. This is what we use when constructing the SCCs for
inference. This is because we compute the value of R1 by unionβing
all the things that it relies on.

This struct brings together a constraint set and a (normal, not
reverse) constraint graph. It implements the graph traits and is
usd for doing the SCC computation.

In reverse mode, a `R1: R2`

constraint results in an edge `R2 -> R1`

. We use this for optimizing liveness computation, because then
we wish to iterate from a region (e.g., R2) to all the regions
that will outlive it (e.g., R1).