# Trait resolution (old-style)
<!-- toc -->
This chapter describes the general process of _trait resolution_ and points out
some non-obvious things.
**Note:** This chapter (and its subchapters) describe how the trait
solver **currently** works. However, we are in the process of
designing a new trait solver. If you'd prefer to read about *that*,
see [*this* subchapter](./chalk.html).
## Major concepts
Trait resolution is the process of pairing up an impl with each
reference to a trait. So, for example, if there is a generic function like:
```rust,ignore
fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> { ... }
```
and then a call to that function:
```rust,ignore
let v: Vec<isize> = clone_slice(&[1, 2, 3])
```
it is the job of trait resolution to figure out whether there exists an impl of
(in this case) `isize : Clone`.
Note that in some cases, like generic functions, we may not be able to
find a specific impl, but we can figure out that the caller must
provide an impl. For example, consider the body of `clone_slice`:
```rust,ignore
fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> {
let mut v = Vec::new();
for e in &x {
v.push((*e).clone()); // (*)
}
}
```
The line marked `(*)` is only legal if `T` (the type of `*e`)
implements the `Clone` trait. Naturally, since we don't know what `T`
is, we can't find the specific impl; but based on the bound `T:Clone`,
we can say that there exists an impl which the caller must provide.
We use the term *obligation* to refer to a trait reference in need of
an impl. Basically, the trait resolution system resolves an obligation
by proving that an appropriate impl does exist.
During type checking, we do not store the results of trait selection.
We simply wish to verify that trait selection will succeed. Then
later, at codegen time, when we have all concrete types available, we
can repeat the trait selection to choose an actual implementation, which
will then be generated in the output binary.
## Overview
Trait resolution consists of three major parts:
- **Selection**: Deciding how to resolve a specific obligation. For
example, selection might decide that a specific obligation can be
resolved by employing an impl which matches the `Self` type, or by using a
parameter bound (e.g. `T: Trait`). In the case of an impl, selecting one
obligation can create *nested obligations* because of where clauses
on the impl itself. It may also require evaluating those nested
obligations to resolve ambiguities.
- **Fulfillment**: The fulfillment code is what tracks that obligations
are completely fulfilled. Basically it is a worklist of obligations
to be selected: once selection is successful, the obligation is
removed from the worklist and any nested obligations are enqueued.
Fulfillment constrains inference variables.
- **Evaluation**: Checks whether obligations holds without constraining
any inference variables. Used by selection.
## Selection
Selection is the process of deciding whether an obligation can be
resolved and, if so, how it is to be resolved (via impl, where clause, etc).
The main interface is the `select()` function, which takes an obligation
and returns a `SelectionResult`. There are three possible outcomes:
- `Ok(Some(selection))` – yes, the obligation can be resolved, and
`selection` indicates how. If the impl was resolved via an impl,
then `selection` may also indicate nested obligations that are required
by the impl.
- `Ok(None)` – we are not yet sure whether the obligation can be
resolved or not. This happens most commonly when the obligation
contains unbound type variables.
- `Err(err)` – the obligation definitely cannot be resolved due to a
type error or because there are no impls that could possibly apply.
The basic algorithm for selection is broken into two big phases:
candidate assembly and confirmation.
Note that because of how lifetime inference works, it is not possible to
give back immediate feedback as to whether a unification or subtype