Clarifications and edits to hrtb chapter
This commit is contained in:
parent
cbd05bc786
commit
e5aca6a8ec
|
|
@ -51,4 +51,3 @@ 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).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
# Higher-ranked trait bounds
|
# Higher-ranked trait bounds
|
||||||
|
|
||||||
One of the more subtle concepts at work are *higher-ranked trait
|
One of the more subtle concepts in trait resolution is *higher-ranked trait
|
||||||
bounds*. An example of such a bound is `for<'a> MyTrait<&'a isize>`.
|
bounds*. An example of such a bound is `for<'a> MyTrait<&'a isize>`.
|
||||||
Let's walk through how selection on higher-ranked trait references
|
Let's walk through how selection on higher-ranked trait references
|
||||||
works.
|
works.
|
||||||
|
|
||||||
## Basic matching and skolemization leaks
|
## Basic matching and skolemization leaks
|
||||||
|
|
||||||
Let's walk through the test `compile-fail/hrtb-just-for-static.rs` to see
|
Suppose we have a trait `Foo`:
|
||||||
how it works. The test starts with the trait `Foo`:
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
trait Foo<X> {
|
trait Foo<X> {
|
||||||
|
|
@ -33,25 +32,34 @@ impl<'a> Foo<&'a isize> for AnyInt { }
|
||||||
|
|
||||||
And the question is, does `AnyInt : for<'a> Foo<&'a isize>`? We want the
|
And the question is, does `AnyInt : for<'a> Foo<&'a isize>`? We want the
|
||||||
answer to be yes. The algorithm for figuring it out is closely related
|
answer to be yes. The algorithm for figuring it out is closely related
|
||||||
to the subtyping for higher-ranked types (which is described in
|
to the subtyping for higher-ranked types (which is described in [here][hrsubtype]
|
||||||
`middle::infer::higher_ranked::doc`, but also in a [paper by SPJ] that
|
and also in a [paper by SPJ]. If you wish to understand higher-ranked
|
||||||
I recommend you read).
|
subtyping, we recommend you read the paper). There are a few parts:
|
||||||
|
|
||||||
1. Skolemize the obligation.
|
**TODO**: We should define _skolemize_.
|
||||||
|
|
||||||
|
1. _Skolemize_ the obligation.
|
||||||
2. Match the impl against the skolemized obligation.
|
2. Match the impl against the skolemized obligation.
|
||||||
3. Check for skolemization leaks.
|
3. Check for _skolemization leaks_.
|
||||||
|
|
||||||
|
[hrsubtype]: https://github.com/rust-lang/rust/tree/master/src/librustc/infer/higher_ranked/README.md
|
||||||
[paper by SPJ]: http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/
|
[paper by SPJ]: http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/
|
||||||
|
|
||||||
So let's work through our example. The first thing we would do is to
|
So let's work through our example.
|
||||||
|
|
||||||
|
1. The first thing we would do is to
|
||||||
skolemize the obligation, yielding `AnyInt : Foo<&'0 isize>` (here `'0`
|
skolemize the obligation, yielding `AnyInt : Foo<&'0 isize>` (here `'0`
|
||||||
represents skolemized region #0). Note that now have no quantifiers;
|
represents skolemized region #0). Note that we now have no quantifiers;
|
||||||
in terms of the compiler type, this changes from a `ty::PolyTraitRef`
|
in terms of the compiler type, this changes from a `ty::PolyTraitRef`
|
||||||
to a `TraitRef`. We would then create the `TraitRef` from the impl,
|
to a `TraitRef`. We would then create the `TraitRef` from the impl,
|
||||||
using fresh variables for it's bound regions (and thus getting
|
using fresh variables for it's bound regions (and thus getting
|
||||||
`Foo<&'$a isize>`, where `'$a` is the inference variable for `'a`). Next
|
`Foo<&'$a isize>`, where `'$a` is the inference variable for `'a`).
|
||||||
|
|
||||||
|
2. Next
|
||||||
we relate the two trait refs, yielding a graph with the constraint
|
we relate the two trait refs, yielding a graph with the constraint
|
||||||
that `'0 == '$a`. Finally, we check for skolemization "leaks" – a
|
that `'0 == '$a`.
|
||||||
|
|
||||||
|
3. Finally, we check for skolemization "leaks" – a
|
||||||
leak is basically any attempt to relate a skolemized region to another
|
leak is basically any attempt to relate a skolemized region to another
|
||||||
skolemized region, or to any region that pre-existed the impl match.
|
skolemized region, or to any region that pre-existed the impl match.
|
||||||
The leak check is done by searching from the skolemized region to find
|
The leak check is done by searching from the skolemized region to find
|
||||||
|
|
@ -75,6 +83,8 @@ skolemized to `'0` and the impl trait reference is instantiated to
|
||||||
like `'static == '0`. This means that the taint set for `'0` is `{'0,
|
like `'static == '0`. This means that the taint set for `'0` is `{'0,
|
||||||
'static}`, which fails the leak check.
|
'static}`, which fails the leak check.
|
||||||
|
|
||||||
|
**TODO**: This is because `'static` is not a region variable but is in the taint set, right?
|
||||||
|
|
||||||
## Higher-ranked trait obligations
|
## Higher-ranked trait obligations
|
||||||
|
|
||||||
Once the basic matching is done, we get to another interesting topic:
|
Once the basic matching is done, we get to another interesting topic:
|
||||||
|
|
@ -96,9 +106,9 @@ impl<X,F> Foo<X> for F
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Now let's say we have a obligation `for<'a> Foo<&'a isize>` and we match
|
Now let's say we have a obligation `Baz: for<'a> Foo<&'a isize>` and we match
|
||||||
this impl. What obligation is generated as a result? We want to get
|
this impl. What obligation is generated as a result? We want to get
|
||||||
`for<'a> Bar<&'a isize>`, but how does that happen?
|
`Baz: for<'a> Bar<&'a isize>`, but how does that happen?
|
||||||
|
|
||||||
After the matching, we are in a position where we have a skolemized
|
After the matching, we are in a position where we have a skolemized
|
||||||
substitution like `X => &'0 isize`. If we apply this substitution to the
|
substitution like `X => &'0 isize`. If we apply this substitution to the
|
||||||
|
|
@ -112,5 +122,4 @@ from. (This is done in `higher_ranked::plug_leaks`). We know that the
|
||||||
leak check passed, so this taint set consists solely of the skolemized
|
leak check passed, so this taint set consists solely of the skolemized
|
||||||
region itself plus various intermediate region variables. We then walk
|
region itself plus various intermediate region variables. We then walk
|
||||||
the trait-reference and convert every region in that taint set back to
|
the trait-reference and convert every region in that taint set back to
|
||||||
a late-bound region, so in this case we'd wind up with `for<'a> F :
|
a late-bound region, so in this case we'd wind up with `Baz: for<'a> Bar<&'a isize>`.
|
||||||
Bar<&'a isize>`.
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue