To help make the current GraphViz output of the dependency graph more
legible, introduce "fake" nodes for the source buffers we encounter,
and draw edges from those nodes to any requests associated with those
source buffers that have no other edges leading to them. This is a
temporary visualization hack, to be replaced by proper "top-level"
requests for things like type-checking an entire source file.
Use the "nearest source location" information on a request to map it
to a particular source buffer, then use that information in the
GraphViz dependency graphs so we can see cross-file dependencies more
clearly.
The bundling of the form of a request (e.g., the storage that makes up a request)
with the function that evaluates the request value requires us to perform
ad hoc indirection to address the AST —> Sema layering violation. For
example, ClassDecl::getSuperclass() calls through the LazyResolver (when
available) to form the appropriate request. This means that we cannot
use the the request-evaluator’s cache when LazyResolver is null, forcing
all cached state into the AST.
Provide the evaluator with a zone-based registration system, where each
request “zone” (e.g., the type checker’s requests) registers
callbacks to evaluate each kind of request within that zone. The
evaluator indirects through this table of function pointers, allowing
the request classes themselves to be available at a lower level (AST)
than the functions that perform the computation when the value isn’t
in the cache (e.g., Sema).
We are not taking advantage of the indirection yet; that’ll come in a
follow-up commit.
When dumping dependencies, clean up the output in two ways:
* Elide redundant but (non-cyclic) references to the same dependency.
* When dumping a cycle, highlight the path to the cycle so it stands out.
As a debugging aid, introduce a new frontend flag `-debug-cycles` that
will emit a debug dump whenever the request-evaluator encounters a cyclic
dependency, while otherwise allowing compilation to continue.
The type checker has *lots* cycles, and producing diagnostics for them
at this point in the development of the request-evaluator is not
productive because it breaks currently-working code. Disable cycle
diagnostics for now when using the request-evaluator in the type
checker. We'll enable it later as things improve, or as a separate
logging mode in the interim.
Introduce another form of debugging dump for the evaluator, rendering the
complete dependency graph using GraphViz, including all dependencies and
values cached within the evaluator.
Perform online tracking of the (direct) dependencies of each request made
to the evaluator, and introduce debugging code to print these dependencies
as a tree (from a particular request).
Turn the `activeRequests` stack into a `SetVector` and use it to detect
cycles. This approach works for uncached requests, and lets us simplify
the external-caching protocol quite a bit because we no longer record
“in-flight” states. Simplify the cache as well.
Thanks to Graydon for the suggestion.
Meant as a replacement for the barely-started iterative type checker,
introduce a simpler "evaluator" that can evaluate individual requests
(essentially, function objects with some additional API), caching
results as appropriate and detecting cycles.