Edits and cleanup in trait-caching subchapter

This commit is contained in:
Mark Mansi 2018-02-12 17:49:56 -06:00
parent e5aca6a8ec
commit a4b5151b11
1 changed files with 28 additions and 16 deletions

View File

@ -1,6 +1,6 @@
# Caching and subtle considerations therewith
In general we attempt to cache the results of trait selection. This
In general, we attempt to cache the results of trait selection. This
is a somewhat complex process. Part of the reason for this is that we
want to be able to cache results even when all the types in the trait
reference are not fully known. In that case, it may happen that the
@ -12,37 +12,43 @@ but *replay* its effects on the type variables.
The high-level idea of how the cache works is that we first replace
all unbound inference variables with skolemized versions. Therefore,
if we had a trait reference `usize : Foo<$1>`, where `$n` is an unbound
inference variable, we might replace it with `usize : Foo<%0>`, where
`%n` is a skolemized type. We would then look this up in the cache.
if we had a trait reference `usize : Foo<$t>`, where `$t` is an unbound
inference variable, we might replace it with `usize : Foo<$0>`, where
`$0` is a skolemized type. We would then look this up in the cache.
If we found a hit, the hit would tell us the immediate next step to
take in the selection process: i.e. apply impl #22, or apply where
clause `X : Foo<Y>`. Let's say in this case there is no hit.
Therefore, we search through impls and where clauses and so forth, and
we come to the conclusion that the only possible impl is this one,
with def-id 22:
take in the selection process (e.g. apply impl #22, or apply where
clause `X : Foo<Y>`).
On the other hand, if there is no hit, we need to go through the [selection
process] from scratch. Suppose, we come to the conclusion that the only
possible impl is this one, with def-id 22:
[selection process]: ./trait-resolution.html#selection
```rust
impl Foo<isize> for usize { ... } // Impl #22
```
We would then record in the cache `usize : Foo<%0> ==>
ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which
would (as a side-effect) unify `$1` with `isize`.
We would then record in the cache `usize : Foo<$0> => ImplCandidate(22)`. Next
we would [confirm] `ImplCandidate(22)`, which would (as a side-effect) unify
`$t` with `isize`.
[confirm]: ./trait-resolution.html#confirmation
Now, at some later time, we might come along and see a `usize :
Foo<$3>`. When skolemized, this would yield `usize : Foo<%0>`, just as
Foo<$u>`. When skolemized, this would yield `usize : Foo<$0>`, just as
before, and hence the cache lookup would succeed, yielding
`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would
(as a side-effect) unify `$3` with `isize`.
(as a side-effect) unify `$u` with `isize`.
## Where clauses and the local vs global cache
One subtle interaction is that the results of trait lookup will vary
depending on what where clauses are in scope. Therefore, we actually
have *two* caches, a local and a global cache. The local cache is
attached to the `ParamEnv` and the global cache attached to the
`tcx`. We use the local cache whenever the result might depend on the
attached to the [`ParamEnv`], and the global cache attached to the
[`tcx`]. We use the local cache whenever the result might depend on the
where clauses that are in scope. The determination of which cache to
use is done by the method `pick_candidate_cache` in `select.rs`. At
the moment, we use a very simple, conservative rule: if there are any
@ -51,3 +57,9 @@ and draw finer-grained distinctions, but that led to a serious of
annoying and weird bugs like #22019 and #18290. This simple rule seems
to be pretty clearly safe and also still retains a very high hit rate
(~95% when compiling rustc).
**TODO**: it looks like `pick_candidate_cache` no longer exists. In
general, is this section still accurate at all?
[`ParamEnv`]: ./param_env.html
[`tcx`]: ./ty.html