Edits and cleanup in trait-caching subchapter
This commit is contained in:
parent
e5aca6a8ec
commit
a4b5151b11
|
|
@ -1,6 +1,6 @@
|
||||||
# Caching and subtle considerations therewith
|
# 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
|
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
|
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
|
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
|
The high-level idea of how the cache works is that we first replace
|
||||||
all unbound inference variables with skolemized versions. Therefore,
|
all unbound inference variables with skolemized versions. Therefore,
|
||||||
if we had a trait reference `usize : Foo<$1>`, where `$n` is an unbound
|
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
|
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.
|
`$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
|
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
|
take in the selection process (e.g. apply impl #22, or apply where
|
||||||
clause `X : Foo<Y>`. Let's say in this case there is no hit.
|
clause `X : Foo<Y>`).
|
||||||
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,
|
On the other hand, if there is no hit, we need to go through the [selection
|
||||||
with def-id 22:
|
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
|
```rust
|
||||||
impl Foo<isize> for usize { ... } // Impl #22
|
impl Foo<isize> for usize { ... } // Impl #22
|
||||||
```
|
```
|
||||||
|
|
||||||
We would then record in the cache `usize : Foo<%0> ==>
|
We would then record in the cache `usize : Foo<$0> => ImplCandidate(22)`. Next
|
||||||
ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which
|
we would [confirm] `ImplCandidate(22)`, which would (as a side-effect) unify
|
||||||
would (as a side-effect) unify `$1` with `isize`.
|
`$t` with `isize`.
|
||||||
|
|
||||||
|
[confirm]: ./trait-resolution.html#confirmation
|
||||||
|
|
||||||
Now, at some later time, we might come along and see a `usize :
|
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
|
before, and hence the cache lookup would succeed, yielding
|
||||||
`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would
|
`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
|
## Where clauses and the local vs global cache
|
||||||
|
|
||||||
One subtle interaction is that the results of trait lookup will vary
|
One subtle interaction is that the results of trait lookup will vary
|
||||||
depending on what where clauses are in scope. Therefore, we actually
|
depending on what where clauses are in scope. Therefore, we actually
|
||||||
have *two* caches, a local and a global cache. The local cache is
|
have *two* caches, a local and a global cache. The local cache is
|
||||||
attached to the `ParamEnv` and the global cache attached to 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
|
[`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
|
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
|
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
|
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
|
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
|
to be pretty clearly safe and also still retains a very high hit rate
|
||||||
(~95% when compiling rustc).
|
(~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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue