about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-12-15 05:44:59 -0500
committerNiko Matsakis <niko@alum.mit.edu>2014-12-19 03:29:31 -0500
commitdab6e70e03b569c72ad74328ad91f48a2e00e44f (patch)
treec51f50ed60afff3ff91499f24190bef9df239f86 /src
parentf45c0ef51e342c552021a80ddd343b0c7175111e (diff)
downloadrust-dab6e70e03b569c72ad74328ad91f48a2e00e44f.tar.gz
rust-dab6e70e03b569c72ad74328ad91f48a2e00e44f.zip
Convert gigantic comment away from `//!` form. It is annoying to
read (`//!` is intrusive) and annoying to edit (must maintain a prefix
on every line). Since the only purpose of a `doc.rs` file is to have a
bunch of text, using `/*!` and `*/` without indentations seems
appropriate.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/traits/doc.rs798
1 files changed, 402 insertions, 396 deletions
diff --git a/src/librustc/middle/traits/doc.rs b/src/librustc/middle/traits/doc.rs
index 62246b77ee9..b0addfa0bd9 100644
--- a/src/librustc/middle/traits/doc.rs
+++ b/src/librustc/middle/traits/doc.rs
@@ -8,399 +8,405 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! # TRAIT RESOLUTION
-//!
-//! This document describes the general process and points out some non-obvious
-//! things.
-//!
-//! ## 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:
-//!
-//!     fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> { ... }
-//!
-//! and then a call to that function:
-//!
-//!     let v: Vec<int> = clone_slice([1, 2, 3].as_slice())
-//!
-//! it is the job of trait resolution to figure out (in which case)
-//! whether there exists an impl of `int : 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. To see what I mean, consider the body of `clone_slice`:
-//!
-//!     fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> {
-//!         let mut v = Vec::new();
-//!         for e in x.iter() {
-//!             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.
-//!
-//! ## 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. 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.
-//!
-//! - COHERENCE: The coherence checks are intended to ensure that there
-//!   are never overlapping impls, where two impls could be used with
-//!   equal precedence.
-//!
-//! ## 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,
-//!   etc.
-//!
-//! The basic algorithm for selection is broken into two big phases:
-//! candidate assembly and confirmation.
-//!
-//! ### Candidate assembly
-//!
-//! Searches for impls/where-clauses/etc that might
-//! possibly be used to satisfy the obligation. Each of those is called
-//! a candidate. To avoid ambiguity, we want to find exactly one
-//! candidate that is definitively applicable. In some cases, we may not
-//! know whether an impl/where-clause applies or not -- this occurs when
-//! the obligation contains unbound inference variables.
-//!
-//! The basic idea for candidate assembly is to do a first pass in which
-//! we identify all possible candidates. During this pass, all that we do
-//! is try and unify the type parameters. (In particular, we ignore any
-//! nested where clauses.) Presuming that this unification succeeds, the
-//! impl is added as a candidate.
-//!
-//! Once this first pass is done, we can examine the set of candidates. If
-//! it is a singleton set, then we are done: this is the only impl in
-//! scope that could possibly apply. Otherwise, we can winnow down the set
-//! of candidates by using where clauses and other conditions. If this
-//! reduced set yields a single, unambiguous entry, we're good to go,
-//! otherwise the result is considered ambiguous.
-//!
-//! #### The basic process: Inferring based on the impls we see
-//!
-//! This process is easier if we work through some examples. Consider
-//! the following trait:
-//!
-//! ```
-//! trait Convert<Target> {
-//!     fn convert(&self) -> Target;
-//! }
-//! ```
-//!
-//! This trait just has one method. It's about as simple as it gets. It
-//! converts from the (implicit) `Self` type to the `Target` type. If we
-//! wanted to permit conversion between `int` and `uint`, we might
-//! implement `Convert` like so:
-//!
-//! ```rust
-//! impl Convert<uint> for int { ... } // int -> uint
-//! impl Convert<int> for uint { ... } // uint -> uint
-//! ```
-//!
-//! Now imagine there is some code like the following:
-//!
-//! ```rust
-//! let x: int = ...;
-//! let y = x.convert();
-//! ```
-//!
-//! The call to convert will generate a trait reference `Convert<$Y> for
-//! int`, where `$Y` is the type variable representing the type of
-//! `y`. When we match this against the two impls we can see, we will find
-//! that only one remains: `Convert<uint> for int`. Therefore, we can
-//! select this impl, which will cause the type of `$Y` to be unified to
-//! `uint`. (Note that while assembling candidates, we do the initial
-//! unifications in a transaction, so that they don't affect one another.)
-//!
-//! There are tests to this effect in src/test/run-pass:
-//!
-//!    traits-multidispatch-infer-convert-source-and-target.rs
-//!    traits-multidispatch-infer-convert-target.rs
-//!
-//! #### Winnowing: Resolving ambiguities
-//!
-//! But what happens if there are multiple impls where all the types
-//! unify? Consider this example:
-//!
-//! ```rust
-//! trait Get {
-//!     fn get(&self) -> Self;
-//! }
-//!
-//! impl<T:Copy> Get for T {
-//!     fn get(&self) -> T { *self }
-//! }
-//!
-//! impl<T:Get> Get for Box<T> {
-//!     fn get(&self) -> Box<T> { box get_it(&**self) }
-//! }
-//! ```
-//!
-//! What happens when we invoke `get_it(&box 1_u16)`, for example? In this
-//! case, the `Self` type is `Box<u16>` -- that unifies with both impls,
-//! because the first applies to all types, and the second to all
-//! boxes. In the olden days we'd have called this ambiguous. But what we
-//! do now is do a second *winnowing* pass that considers where clauses
-//! and attempts to remove candidates -- in this case, the first impl only
-//! applies if `Box<u16> : Copy`, which doesn't hold. After winnowing,
-//! then, we are left with just one candidate, so we can proceed. There is
-//! a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`.
-//!
-//! #### Matching
-//!
-//! The subroutines that decide whether a particular impl/where-clause/etc
-//! applies to a particular obligation. At the moment, this amounts to
-//! unifying the self types, but in the future we may also recursively
-//! consider some of the nested obligations, in the case of an impl.
-//!
-//! #### Lifetimes and selection
-//!
-//! Because of how that lifetime inference works, it is not possible to
-//! give back immediate feedback as to whether a unification or subtype
-//! relationship between lifetimes holds or not. Therefore, lifetime
-//! matching is *not* considered during selection. This is reflected in
-//! the fact that subregion assignment is infallible. This may yield
-//! lifetime constraints that will later be found to be in error (in
-//! contrast, the non-lifetime-constraints have already been checked
-//! during selection and can never cause an error, though naturally they
-//! may lead to other errors downstream).
-//!
-//! #### Where clauses
-//!
-//! Besides an impl, the other major way to resolve an obligation is via a
-//! where clause. The selection process is always given a *parameter
-//! environment* which contains a list of where clauses, which are
-//! basically obligations that can assume are satisfiable. We will iterate
-//! over that list and check whether our current obligation can be found
-//! in that list, and if so it is considered satisfied. More precisely, we
-//! want to check whether there is a where-clause obligation that is for
-//! the same trait (or some subtrait) and for which the self types match,
-//! using the definition of *matching* given above.
-//!
-//! Consider this simple example:
-//!
-//!      trait A1 { ... }
-//!      trait A2 : A1 { ... }
-//!
-//!      trait B { ... }
-//!
-//!      fn foo<X:A2+B> { ... }
-//!
-//! Clearly we can use methods offered by `A1`, `A2`, or `B` within the
-//! body of `foo`. In each case, that will incur an obligation like `X :
-//! A1` or `X : A2`. The parameter environment will contain two
-//! where-clauses, `X : A2` and `X : B`. For each obligation, then, we
-//! search this list of where-clauses.  To resolve an obligation `X:A1`,
-//! we would note that `X:A2` implies that `X:A1`.
-//!
-//! ### Confirmation
-//!
-//! Confirmation unifies the output type parameters of the trait with the
-//! values found in the obligation, possibly yielding a type error.  If we
-//! return to our example of the `Convert` trait from the previous
-//! section, confirmation is where an error would be reported, because the
-//! impl specified that `T` would be `uint`, but the obligation reported
-//! `char`. Hence the result of selection would be an error.
-//!
-//! ### Selection during translation
-//!
-//! 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 trans time, when we have all concrete types available, we
-//! can repeat the trait selection.  In this case, we do not consider any
-//! where-clauses to be in scope. We know that therefore each resolution
-//! will resolve to a particular impl.
-//!
-//! One interesting twist has to do with nested obligations. In general, in trans,
-//! we only need to do a "shallow" selection for an obligation. That is, we wish to
-//! identify which impl applies, but we do not (yet) need to decide how to select
-//! any nested obligations. Nonetheless, we *do* currently do a complete resolution,
-//! and that is because it can sometimes inform the results of type inference. That is,
-//! we do not have the full substitutions in terms of the type varibales of the impl available
-//! to us, so we must run trait selection to figure everything out.
-//!
-//! Here is an example:
-//!
-//!     trait Foo { ... }
-//!     impl<U,T:Bar<U>> Foo for Vec<T> { ... }
-//!
-//!     impl Bar<uint> for int { ... }
-//!
-//! After one shallow round of selection for an obligation like `Vec<int>
-//! : Foo`, we would know which impl we want, and we would know that
-//! `T=int`, but we do not know the type of `U`.  We must select the
-//! nested obligation `int : Bar<U>` to find out that `U=uint`.
-//!
-//! It would be good to only do *just as much* nested resolution as
-//! necessary. Currently, though, we just do a full resolution.
-//!
-//! ## Method matching
-//!
-//! Method dispach follows a slightly different path than normal trait
-//! selection. This is because it must account for the transformed self
-//! type of the receiver and various other complications. The procedure is
-//! described in `select.rs` in the "METHOD MATCHING" section.
-//!
-//! # Caching and subtle considerations therewith
-//!
-//! 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
-//! 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
-//! trait selection process is also influencing type variables, so we have
-//! to be able to not only cache the *result* of the selection process,
-//! but *replay* its effects on the type variables.
-//!
-//! ## An example
-//!
-//! The high-level idea of how the cache works is that we first replace
-//! all unbound inference variables with skolemized versions. Therefore,
-//! if we had a trait reference `uint : Foo<$1>`, where `$n` is an unbound
-//! inference variable, we might replace it with `uint : Foo<%0>`, where
-//! `%n` 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
-//! take in the selection process: i.e., apply impl #22, or apply where
-//! clause `X : Foo<Y>`. Let's say in this case there is no hit.
-//! 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,
-//! with def-id 22:
-//!
-//!     impl Foo<int> for uint { ... } // Impl #22
-//!
-//! We would then record in the cache `uint : Foo<%0> ==>
-//! ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which
-//! would (as a side-effect) unify `$1` with `int`.
-//!
-//! Now, at some later time, we might come along and see a `uint :
-//! Foo<$3>`.  When skolemized, this would yield `uint : Foo<%0>`, just as
-//! before, and hence the cache lookup would succeed, yielding
-//! `ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would
-//! (as a side-effect) unify `$3` with `int`.
-//!
-//! ## Where clauses and the local vs global cache
-//!
-//! One subtle interaction is that the results of trait lookup will vary
-//! depending on what where clauses are in scope. Therefore, we actually
-//! have *two* caches, a local and a global cache. The local cache is
-//! attached to the `ParameterEnvironment` and the global cache attached
-//! to 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 use is done by the method `pick_candidate_cache` in
-//! `select.rs`.
-//!
-//! There are two cases where we currently use the local cache. The
-//! current rules are probably more conservative than necessary.
-//!
-//! ### Trait references that involve parameter types
-//!
-//! The most obvious case where you need the local environment is
-//! when the trait reference includes parameter types. For example,
-//! consider the following function:
-//!
-//!     impl<T> Vec<T> {
-//!         fn foo(x: T)
-//!             where T : Foo
-//!         { ... }
-//!
-//!         fn bar(x: T)
-//!         { ... }
-//!     }
-//!
-//! If there is an obligation `T : Foo`, or `int : Bar<T>`, or whatever,
-//! clearly the results from `foo` and `bar` are potentially different,
-//! since the set of where clauses in scope are different.
-//!
-//! ### Trait references with unbound variables when where clauses are in scope
-//!
-//! There is another less obvious interaction which involves unbound variables
-//! where *only* where clauses are in scope (no impls). This manifested as
-//! issue #18209 (`run-pass/trait-cache-issue-18209.rs`). Consider
-//! this snippet:
-//!
-//! ```
-//! pub trait Foo {
-//!     fn load_from() -> Box<Self>;
-//!     fn load() -> Box<Self> {
-//!         Foo::load_from()
-//!     }
-//! }
-//! ```
-//!
-//! The default method will incur an obligation `$0 : Foo` from the call
-//! to `load_from`. If there are no impls, this can be eagerly resolved to
-//! `VtableParam(Self : Foo)` and cached. Because the trait reference
-//! doesn't involve any parameters types (only the resolution does), this
-//! result was stored in the global cache, causing later calls to
-//! `Foo::load_from()` to get nonsense.
-//!
-//! To fix this, we always use the local cache if there are unbound
-//! variables and where clauses in scope. This is more conservative than
-//! necessary as far as I can tell. However, it still seems to be a simple
-//! rule and I observe ~99% hit rate on rustc, so it doesn't seem to hurt
-//! us in particular.
-//!
-//! Here is an example of the kind of subtle case that I would be worried
-//! about with a more complex rule (although this particular case works
-//! out ok). Imagine the trait reference doesn't directly reference a
-//! where clause, but the where clause plays a role in the winnowing
-//! phase. Something like this:
-//!
-//! ```
-//! pub trait Foo<T> { ... }
-//! pub trait Bar { ... }
-//! impl<U,T:Bar> Foo<U> for T { ... } // Impl A
-//! impl Foo<char> for uint { ... }    // Impl B
-//! ```
-//!
-//! Now, in some function, we have no where clauses in scope, and we have
-//! an obligation `$1 : Foo<$0>`. We might then conclude that `$0=char`
-//! and `$1=uint`: this is because for impl A to apply, `uint:Bar` would
-//! have to hold, and we know it does not or else the coherence check
-//! would have failed.  So we might enter into our global cache: `$1 :
-//! Foo<$0> => Impl B`.  Then we come along in a different scope, where a
-//! generic type `A` is around with the bound `A:Bar`. Now suddenly the
-//! impl is viable.
-//!
-//! The flaw in this imaginary DOOMSDAY SCENARIO is that we would not
-//! currently conclude that `$1 : Foo<$0>` implies that `$0 == uint` and
-//! `$1 == char`, even though it is true that (absent type parameters)
-//! there is no other type the user could enter. However, it is not
-//! *completely* implausible that we *could* draw this conclusion in the
-//! future; we wouldn't have to guess types, in particular, we could be
-//! led by the impls.
+/*!
+
+# TRAIT RESOLUTION
+
+This document describes the general process and points out some non-obvious
+things.
+
+## 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:
+
+    fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> { ... }
+
+and then a call to that function:
+
+    let v: Vec<int> = clone_slice([1, 2, 3].as_slice())
+
+it is the job of trait resolution to figure out (in which case)
+whether there exists an impl of `int : 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. To see what I mean, consider the body of `clone_slice`:
+
+    fn clone_slice<T:Clone>(x: &[T]) -> Vec<T> {
+        let mut v = Vec::new();
+        for e in x.iter() {
+            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.
+
+## 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. 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.
+
+- COHERENCE: The coherence checks are intended to ensure that there
+  are never overlapping impls, where two impls could be used with
+  equal precedence.
+
+## 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,
+  etc.
+
+The basic algorithm for selection is broken into two big phases:
+candidate assembly and confirmation.
+
+### Candidate assembly
+
+Searches for impls/where-clauses/etc that might
+possibly be used to satisfy the obligation. Each of those is called
+a candidate. To avoid ambiguity, we want to find exactly one
+candidate that is definitively applicable. In some cases, we may not
+know whether an impl/where-clause applies or not -- this occurs when
+the obligation contains unbound inference variables.
+
+The basic idea for candidate assembly is to do a first pass in which
+we identify all possible candidates. During this pass, all that we do
+is try and unify the type parameters. (In particular, we ignore any
+nested where clauses.) Presuming that this unification succeeds, the
+impl is added as a candidate.
+
+Once this first pass is done, we can examine the set of candidates. If
+it is a singleton set, then we are done: this is the only impl in
+scope that could possibly apply. Otherwise, we can winnow down the set
+of candidates by using where clauses and other conditions. If this
+reduced set yields a single, unambiguous entry, we're good to go,
+otherwise the result is considered ambiguous.
+
+#### The basic process: Inferring based on the impls we see
+
+This process is easier if we work through some examples. Consider
+the following trait:
+
+```
+trait Convert<Target> {
+    fn convert(&self) -> Target;
+}
+```
+
+This trait just has one method. It's about as simple as it gets. It
+converts from the (implicit) `Self` type to the `Target` type. If we
+wanted to permit conversion between `int` and `uint`, we might
+implement `Convert` like so:
+
+```rust
+impl Convert<uint> for int { ... } // int -> uint
+impl Convert<int> for uint { ... } // uint -> uint
+```
+
+Now imagine there is some code like the following:
+
+```rust
+let x: int = ...;
+let y = x.convert();
+```
+
+The call to convert will generate a trait reference `Convert<$Y> for
+int`, where `$Y` is the type variable representing the type of
+`y`. When we match this against the two impls we can see, we will find
+that only one remains: `Convert<uint> for int`. Therefore, we can
+select this impl, which will cause the type of `$Y` to be unified to
+`uint`. (Note that while assembling candidates, we do the initial
+unifications in a transaction, so that they don't affect one another.)
+
+There are tests to this effect in src/test/run-pass:
+
+   traits-multidispatch-infer-convert-source-and-target.rs
+   traits-multidispatch-infer-convert-target.rs
+
+#### Winnowing: Resolving ambiguities
+
+But what happens if there are multiple impls where all the types
+unify? Consider this example:
+
+```rust
+trait Get {
+    fn get(&self) -> Self;
+}
+
+impl<T:Copy> Get for T {
+    fn get(&self) -> T { *self }
+}
+
+impl<T:Get> Get for Box<T> {
+    fn get(&self) -> Box<T> { box get_it(&**self) }
+}
+```
+
+What happens when we invoke `get_it(&box 1_u16)`, for example? In this
+case, the `Self` type is `Box<u16>` -- that unifies with both impls,
+because the first applies to all types, and the second to all
+boxes. In the olden days we'd have called this ambiguous. But what we
+do now is do a second *winnowing* pass that considers where clauses
+and attempts to remove candidates -- in this case, the first impl only
+applies if `Box<u16> : Copy`, which doesn't hold. After winnowing,
+then, we are left with just one candidate, so we can proceed. There is
+a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`.
+
+#### Matching
+
+The subroutines that decide whether a particular impl/where-clause/etc
+applies to a particular obligation. At the moment, this amounts to
+unifying the self types, but in the future we may also recursively
+consider some of the nested obligations, in the case of an impl.
+
+#### Lifetimes and selection
+
+Because of how that lifetime inference works, it is not possible to
+give back immediate feedback as to whether a unification or subtype
+relationship between lifetimes holds or not. Therefore, lifetime
+matching is *not* considered during selection. This is reflected in
+the fact that subregion assignment is infallible. This may yield
+lifetime constraints that will later be found to be in error (in
+contrast, the non-lifetime-constraints have already been checked
+during selection and can never cause an error, though naturally they
+may lead to other errors downstream).
+
+#### Where clauses
+
+Besides an impl, the other major way to resolve an obligation is via a
+where clause. The selection process is always given a *parameter
+environment* which contains a list of where clauses, which are
+basically obligations that can assume are satisfiable. We will iterate
+over that list and check whether our current obligation can be found
+in that list, and if so it is considered satisfied. More precisely, we
+want to check whether there is a where-clause obligation that is for
+the same trait (or some subtrait) and for which the self types match,
+using the definition of *matching* given above.
+
+Consider this simple example:
+
+     trait A1 { ... }
+     trait A2 : A1 { ... }
+
+     trait B { ... }
+
+     fn foo<X:A2+B> { ... }
+
+Clearly we can use methods offered by `A1`, `A2`, or `B` within the
+body of `foo`. In each case, that will incur an obligation like `X :
+A1` or `X : A2`. The parameter environment will contain two
+where-clauses, `X : A2` and `X : B`. For each obligation, then, we
+search this list of where-clauses.  To resolve an obligation `X:A1`,
+we would note that `X:A2` implies that `X:A1`.
+
+### Confirmation
+
+Confirmation unifies the output type parameters of the trait with the
+values found in the obligation, possibly yielding a type error.  If we
+return to our example of the `Convert` trait from the previous
+section, confirmation is where an error would be reported, because the
+impl specified that `T` would be `uint`, but the obligation reported
+`char`. Hence the result of selection would be an error.
+
+### Selection during translation
+
+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 trans time, when we have all concrete types available, we
+can repeat the trait selection.  In this case, we do not consider any
+where-clauses to be in scope. We know that therefore each resolution
+will resolve to a particular impl.
+
+One interesting twist has to do with nested obligations. In general, in trans,
+we only need to do a "shallow" selection for an obligation. That is, we wish to
+identify which impl applies, but we do not (yet) need to decide how to select
+any nested obligations. Nonetheless, we *do* currently do a complete resolution,
+and that is because it can sometimes inform the results of type inference. That is,
+we do not have the full substitutions in terms of the type varibales of the impl available
+to us, so we must run trait selection to figure everything out.
+
+Here is an example:
+
+    trait Foo { ... }
+    impl<U,T:Bar<U>> Foo for Vec<T> { ... }
+
+    impl Bar<uint> for int { ... }
+
+After one shallow round of selection for an obligation like `Vec<int>
+: Foo`, we would know which impl we want, and we would know that
+`T=int`, but we do not know the type of `U`.  We must select the
+nested obligation `int : Bar<U>` to find out that `U=uint`.
+
+It would be good to only do *just as much* nested resolution as
+necessary. Currently, though, we just do a full resolution.
+
+## Method matching
+
+Method dispach follows a slightly different path than normal trait
+selection. This is because it must account for the transformed self
+type of the receiver and various other complications. The procedure is
+described in `select.rs` in the "METHOD MATCHING" section.
+
+# Caching and subtle considerations therewith
+
+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
+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
+trait selection process is also influencing type variables, so we have
+to be able to not only cache the *result* of the selection process,
+but *replay* its effects on the type variables.
+
+## An example
+
+The high-level idea of how the cache works is that we first replace
+all unbound inference variables with skolemized versions. Therefore,
+if we had a trait reference `uint : Foo<$1>`, where `$n` is an unbound
+inference variable, we might replace it with `uint : Foo<%0>`, where
+`%n` 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
+take in the selection process: i.e., apply impl #22, or apply where
+clause `X : Foo<Y>`. Let's say in this case there is no hit.
+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,
+with def-id 22:
+
+    impl Foo<int> for uint { ... } // Impl #22
+
+We would then record in the cache `uint : Foo<%0> ==>
+ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which
+would (as a side-effect) unify `$1` with `int`.
+
+Now, at some later time, we might come along and see a `uint :
+Foo<$3>`.  When skolemized, this would yield `uint : Foo<%0>`, just as
+before, and hence the cache lookup would succeed, yielding
+`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would
+(as a side-effect) unify `$3` with `int`.
+
+## Where clauses and the local vs global cache
+
+One subtle interaction is that the results of trait lookup will vary
+depending on what where clauses are in scope. Therefore, we actually
+have *two* caches, a local and a global cache. The local cache is
+attached to the `ParameterEnvironment` and the global cache attached
+to 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 use is done by the method `pick_candidate_cache` in
+`select.rs`.
+
+There are two cases where we currently use the local cache. The
+current rules are probably more conservative than necessary.
+
+### Trait references that involve parameter types
+
+The most obvious case where you need the local environment is
+when the trait reference includes parameter types. For example,
+consider the following function:
+
+    impl<T> Vec<T> {
+        fn foo(x: T)
+            where T : Foo
+        { ... }
+
+        fn bar(x: T)
+        { ... }
+    }
+
+If there is an obligation `T : Foo`, or `int : Bar<T>`, or whatever,
+clearly the results from `foo` and `bar` are potentially different,
+since the set of where clauses in scope are different.
+
+### Trait references with unbound variables when where clauses are in scope
+
+There is another less obvious interaction which involves unbound variables
+where *only* where clauses are in scope (no impls). This manifested as
+issue #18209 (`run-pass/trait-cache-issue-18209.rs`). Consider
+this snippet:
+
+```
+pub trait Foo {
+    fn load_from() -> Box<Self>;
+    fn load() -> Box<Self> {
+        Foo::load_from()
+    }
+}
+```
+
+The default method will incur an obligation `$0 : Foo` from the call
+to `load_from`. If there are no impls, this can be eagerly resolved to
+`VtableParam(Self : Foo)` and cached. Because the trait reference
+doesn't involve any parameters types (only the resolution does), this
+result was stored in the global cache, causing later calls to
+`Foo::load_from()` to get nonsense.
+
+To fix this, we always use the local cache if there are unbound
+variables and where clauses in scope. This is more conservative than
+necessary as far as I can tell. However, it still seems to be a simple
+rule and I observe ~99% hit rate on rustc, so it doesn't seem to hurt
+us in particular.
+
+Here is an example of the kind of subtle case that I would be worried
+about with a more complex rule (although this particular case works
+out ok). Imagine the trait reference doesn't directly reference a
+where clause, but the where clause plays a role in the winnowing
+phase. Something like this:
+
+```
+pub trait Foo<T> { ... }
+pub trait Bar { ... }
+impl<U,T:Bar> Foo<U> for T { ... } // Impl A
+impl Foo<char> for uint { ... }    // Impl B
+```
+
+Now, in some function, we have no where clauses in scope, and we have
+an obligation `$1 : Foo<$0>`. We might then conclude that `$0=char`
+and `$1=uint`: this is because for impl A to apply, `uint:Bar` would
+have to hold, and we know it does not or else the coherence check
+would have failed.  So we might enter into our global cache: `$1 :
+Foo<$0> => Impl B`.  Then we come along in a different scope, where a
+generic type `A` is around with the bound `A:Bar`. Now suddenly the
+impl is viable.
+
+The flaw in this imaginary DOOMSDAY SCENARIO is that we would not
+currently conclude that `$1 : Foo<$0>` implies that `$0 == uint` and
+`$1 == char`, even though it is true that (absent type parameters)
+there is no other type the user could enter. However, it is not
+*completely* implausible that we *could* draw this conclusion in the
+future; we wouldn't have to guess types, in particular, we could be
+led by the impls.
+
+
+
+*/