Trait logic: Explain what each domain goal means

This commit is contained in:
Tyler Mandry 2018-05-25 23:03:09 -04:00 committed by Who? Me?!
parent 3ea4a0b683
commit 01f9d655ee
2 changed files with 73 additions and 24 deletions

View File

@ -67,7 +67,7 @@ its inputs P0..Pm:
Projection = <P0 as TraitName<P1..Pn>>::AssocItem<Pn+1..Pm> Projection = <P0 as TraitName<P1..Pn>>::AssocItem<Pn+1..Pm>
``` ```
Given that, we can define a `DomainGoal` as follows: Given these, we can define a `DomainGoal` as follows:
```text ```text
DomainGoal = Implemented(TraitRef) DomainGoal = Implemented(TraitRef)
@ -78,33 +78,82 @@ DomainGoal = Implemented(TraitRef)
| WellFormed(Type) | WellFormed(Type)
| WellFormed(TraitRef) | WellFormed(TraitRef)
| WellFormed(Projection = Type) | WellFormed(Projection = Type)
| Outlives(Type, Region) | Outlives(Type: Region)
| Outlives(Region, Region) | Outlives(Region: Region)
``` ```
- `Implemented(TraitRef)` -- true if the given trait is Let's break down each one of these, one-by-one.
implemented for the given input types and lifetimes
- `FromEnv(TraitEnv)` -- true if the given trait is *assumed* to be implemented; #### Implemented(TraitRef)
that is, if it can be derived from the in-scope where clauses e.g. `Implemented(i32: Copy)`
- as we'll see in the section on lowering, `FromEnv(X)` implies
`Implemented(X)` but not vice versa. This distinction is crucial True if the given trait is implemented for the given input types and lifetimes.
to [implied bounds].
- `ProjectionEq(Projection = Type)` -- the given associated type `Projection` #### ProjectionEq(Projection = Type)
is equal to `Type`; see [the section on associated e.g. `ProjectionEq<T as Iterator>::Item = u8`
types](./traits-associated-types.html)
- in general, proving `ProjectionEq(TraitRef::Item = Type)` also The given associated type `Projection` is equal to `Type`; this can be proved
requires proving `Implemented(TraitRef)` with either normalization or using skolemized types. See [the section
- `Normalize(Projection -> Type)` -- the given associated type `Projection` can on associated types](./traits-associated-types.html).
be [normalized][n] to `Type`
- as discussed in [the section on associated #### Normalize(Projection -> Type)
types](./traits-associated-types.html), e.g. `ProjectionEq<T as Iterator>::Item -> u8`
`Normalize` implies `ProjectionEq` but not vice versa
- `WellFormed(..)` -- these goals imply that the given item is The given associated type `Projection` can be [normalized][n] to `Type`.
*well-formed*
- well-formedness is important to [implied bounds]. As discussed in [the section on associated
types](./traits-associated-types.html), `Normalize` implies `ProjectionEq`,
but not vice versa. In general, proving `Normalize(<T as Trait>::Item -> U)`
also requires proving `Implemented(T: Trait)`.
[n]: ./traits-associated-types.html#normalize [n]: ./traits-associated-types.html#normalize
#### FromEnv(TraitRef), FromEnv(Projection = Type)
e.g. `FromEnv(Self: Add<i32>)`
e.g. `FromEnv(<Self as StreamingIterator>::Item<'a> = &'a [u8])`
True if the inner `TraitRef` or projection equality is *assumed* to be true;
that is, if it can be derived from the in-scope where clauses.
For example, given the following function:
```rust
fn loud_clone<T: Clone>(stuff: &T) -> T {
println!("cloning!");
stuff.clone()
}
```
Inside the body of our function, we would have `FromEnv(T: Clone)`. In-scope
where clauses nest, so a function body inside an impl body inherits the
impl body's where clauses, too.
This and the next rule are used to implement [implied bounds]. As we'll see
in the section on lowering, `FromEnv(X)` implies `Implemented(X)`, but not
vice versa. This distinction is crucial to implied bounds.
#### WellFormed(Item)
These goals imply that the given item is *well-formed*.
We can talk about different types of items being well-formed:
**Types**, like `WellFormed(Vec<i32>)`, which is true in Rust, or
`WellFormed(Vec<str>)`, which is not (because `str` is not `Sized`.)
**TraitRefs**, like `WellFormed(Vec<i32>: Clone)`.
**Projections**, like `WellFormed(T: Iterator<Item = u32>)`.
Well-formedness is important to [implied bounds]. In particular, the reason
it is okay to assume `FromEnv(T: Clone)` in the example above is that we
_also_ verify `WellFormed(T: Clone)` for each call site of `loud_clone`.
#### Outlives(Type: Region), Outlives(Region: Region)
e.g. `Outlives(&'a str: 'b)`, `Outlives('a: 'static)`
True if the given type or region on the left outlives the right-hand region.
<a name="coinductive"></a> <a name="coinductive"></a>
## Coinductive goals ## Coinductive goals

View File

@ -113,7 +113,7 @@ forall<Self, P1..Pn> {
``` ```
This clause says that if we are assuming that the trait holds, then we can also This clause says that if we are assuming that the trait holds, then we can also
assume that it's where-clauses hold. It's perhaps useful to see an example: assume that its where-clauses hold. It's perhaps useful to see an example:
```rust,ignore ```rust,ignore
trait Eq: PartialEq { ... } trait Eq: PartialEq { ... }