tcx.type_check_item(item_def_id);
}
}
```
We see that the `type_check_crate` query accesses input data
(`tcx.hir_map.list_of_items()`) and invokes other queries
(`type_check_item`). The `type_check_item`
invocations will themselves access input data and/or invoke other queries,
so that in the end the DAG of query invocations will be built up backwards
from the node that was initially executed:
```ignore
(2) (1)
list_of_all_hir_items <----------------------------- type_check_crate()
|
(5) (4) (3) |
Hir(foo) <--- type_of(foo) <--- type_check_item(foo) <-------+
| |
+-----------------+ |
| |
(7) v (6) (8) |
Hir(bar) <--- type_of(bar) <--- type_check_item(bar) <-------+
// (x) denotes invocation order
```
We also see that often a query result can be read from the cache:
`type_of(bar)` was computed for `type_check_item(foo)` so when
`type_check_item(bar)` needs it, it is already in the cache.
Query results stay cached in the query context as long as the context lives.
So if the compiler driver invoked another query later on, the above graph
would still exist and already executed queries would not have to be re-done.
## Cycles
Earlier we stated that query invocations form a DAG. However, it would be easy
to form a cyclic graph by, for example, having a query provider like the
following:
```rust,ignore
fn cyclic_query_provider(tcx, key) -> u32 {
// Invoke the same query with the same key again
tcx.cyclic_query(key)
}
```
Since query providers are regular functions, this would behave much as expected:
Evaluation would get stuck in an infinite recursion. A query like this would not
be very useful either. However, sometimes certain kinds of invalid user input