src/doc/rustc-dev-guide/src/traits/caching.md MARKDOWN 68 lines View on github.com → Search inside
1# Caching and subtle considerations therewith23In general, we attempt to cache the results of trait selection.  This4is a somewhat complex process. Part of the reason for this is that we5want to be able to cache results even when all the types in the trait6reference are not fully known. In that case, it may happen that the7trait selection process is also influencing type variables, so we have8to be able to not only cache the *result* of the selection process,9but *replay* its effects on the type variables.1011## An example1213The high-level idea of how the cache works is that we first replace14all unbound inference variables with placeholder versions. Therefore,15if we had a trait reference `usize : Foo<$t>`, where `$t` is an unbound16inference variable, we might replace it with `usize : Foo<$0>`, where17`$0` is a placeholder type. We would then look this up in the cache.1819If we found a hit, the hit would tell us the immediate next step to20take in the selection process (e.g. apply impl #22, or apply where21clause `X : Foo<Y>`).2223On the other hand, if there is no hit, we need to go through the [selection24process] from scratch. Suppose, we come to the conclusion that the only25possible impl is this one, with def-id 22:2627[selection process]: ./resolution.html#selection2829```rust,ignore30impl Foo<isize> for usize { ... } // Impl #2231```3233We would then record in the cache `usize : Foo<$0> => ImplCandidate(22)`. Next34we would [confirm] `ImplCandidate(22)`, which would (as a side-effect) unify35`$t` with `isize`.3637[confirm]: ./resolution.html#confirmation3839Now, at some later time, we might come along and see a `usize :40Foo<$u>`. When replaced with a placeholder, this would yield `usize : Foo<$0>`, just as41before, and hence the cache lookup would succeed, yielding42`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would43(as a side-effect) unify `$u` with `isize`.4445## Where clauses and the local vs global cache4647One subtle interaction is that the results of trait lookup will vary48depending on what where clauses are in scope. Therefore, we actually49have *two* caches, a local and a global cache. The local cache is50attached to the [`ParamEnv`], and the global cache attached to the51[`tcx`]. We use the local cache whenever the result might depend on the52where clauses that are in scope. The determination of which cache to53use is done by the method `pick_candidate_cache` in `select.rs`. At54the moment, we use a very simple, conservative rule: if there are any55where-clauses in scope, then we use the local cache.  We used to try56and draw finer-grained distinctions, but that led to a series of57annoying and weird bugs like [#22019] and [#18290]. This simple rule seems58to be pretty clearly safe and also still retains a very high hit rate59(~95% when compiling rustc).6061**TODO**: it looks like `pick_candidate_cache` no longer exists. In62general, is this section still accurate at all?6364[`ParamEnv`]: ../typing-parameter-envs.html65[`tcx`]: ../ty.html66[#18290]: https://github.com/rust-lang/rust/issues/1829067[#22019]: https://github.com/rust-lang/rust/issues/22019

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.