# Coinduction
The trait solver may use coinduction when proving goals.
Coinduction is fairly subtle so we're giving it its own chapter.
## Coinduction and induction
With induction, we recursively apply proofs until we end up with a finite proof tree.
Consider the example of `Vec<Vec<Vec<u32>>>: Debug` which results in the following tree.
- `Vec<Vec<Vec<u32>>>: Debug`
- `Vec<Vec<u32>>: Debug`
- `Vec<u32>: Debug`
- `u32: Debug`
This tree is finite. But not all goals we would want to hold have finite proof trees,
consider the following example:
```rust
struct List<T> {
value: T,
next: Option<Box<List<T>>>,
}
```
For `List<T>: Send` to hold all its fields have to recursively implement `Send` as well.
This would result in the following proof tree:
- `List<T>: Send`
- `T: Send`
- `Option<Box<List<T>>>: Send`
- `Box<List<T>>: Send`
- `List<T>: Send`
- `T: Send`
- `Option<Box<List<T>>>: Send`
- `Box<List<T>>: Send`
- ...
This tree would be infinitely large which is exactly what coinduction is about.
> To **inductively** prove a goal you need to provide a finite proof tree for it.
> To **coinductively** prove a goal the provided proof tree may be infinite.
## Why is coinduction correct
When checking whether some trait goals holds, we're asking "does there exist an `impl`
which satisfies this bound". Even if are infinite chains of nested goals, we still have a
unique `impl` which should be used.
## How to implement coinduction
While our implementation can not check for coinduction by trying to construct an infinite
tree as that would take infinite resources, it still makes sense to think of coinduction
from this perspective.
As we cannot check for infinite trees, we instead search for patterns for which we know that
they would result in an infinite proof tree. The currently pattern we detect are (canonical)
cycles. If `T: Send` relies on `T: Send` then it's pretty clear that this will just go on forever.
With cycles we have to be careful with caching. Because of canonicalization of regions and
inference variables encountering a cycle doesn't mean that we would get an infinite proof tree.
Looking at the following example:
```rust
trait Foo {}
struct Wrapper<T>(T);
impl<T> Foo for Wrapper<Wrapper<T>>
where
Wrapper<T>: Foo
{}
```
Proving `Wrapper<?0>: Foo` uses the impl `impl<T> Foo for Wrapper<Wrapper<T>>` which constrains
`?0` to `Wrapper<?1>` and then requires `Wrapper<?1>: Foo`. Due to canonicalization this would be
detected as a cycle.
The idea to solve is to return a *provisional result* whenever we detect a cycle and repeatedly
retry goals until the *provisional result* is equal to the final result of that goal. We
start out by using `Yes` with no constraints as the result and then update it to the result of
the previous iteration whenever we have to rerun.
TODO: elaborate here. We use the same approach as chalk for coinductive cycles.
Note that the treatment for inductive cycles currently differs by simply returning `Overflow`.
See [the relevant chapters][chalk] in the chalk book.
## Future work
We currently only consider auto-traits, `Sized`, and `WF`-goals to be coinductive.
In the future we pretty much intend for all goals to be coinductive.
Lets first elaborate on why allowing more coinductive proofs is even desirable.
### Recursive data types already rely on coinduction...
...they just tend to avoid them in the trait solver.
```rust
enum List<T> {
Nil,
Succ(T, Box<List<T>>),
}
impl<T: Clone> Clone for List<T> {
fn clone(&self) -> Self {
match self {
List::Nil => List::Nil,
List::Succ(head, tail) => List::Succ(head.clone(), tail.clone()),
}
}
}
```
We are using `tail.clone()` in this impl. For this we have to prove `Box<List<T>>: Clone`
which requires `List<T>: Clone` but that relies on the impl which we are currently checking.