diff --git a/src/librustc/middle/traits/README.md b/src/librustc/middle/traits/README.md index 92982af92dcfe7ad772500cb809f66812070bafa..ff72f9dd07e36096819e2244644099a136cc63c4 100644 --- a/src/librustc/middle/traits/README.md +++ b/src/librustc/middle/traits/README.md @@ -428,3 +428,43 @@ We used to try and draw finer-grained distinctions, but that led to a serious of 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 (~95% when compiling rustc). + +# Specialization + +Defined in the `specialize` module. + +The basic strategy is to build up a *specialization graph* during +coherence checking. Insertion into the graph locates the right place +to put an impl in the specialization hierarchy; if there is no right +place (due to partial overlap but no containment), you get an overlap +error. Specialization is consulted when selecting an impl (of course), +and the graph is consulted when propagating defaults down the +specialization hierarchy. + +You might expect that the specialization graph would be used during +selection -- i.e., when actually performing specialization. This is +not done for two reasons: + +- It's merely an optimization: given a set of candidates that apply, + we can determine the most specialized one by comparing them directly + for specialization, rather than consulting the graph. Given that we + also cache the results of selection, the benefit of this + optimization is questionable. + +- To build the specialization graph in the first place, we need to use + selection (because we need to determine whether one impl specializes + another). Dealing with this reentrancy would require some additional + mode switch for selection. Given that there seems to be no strong + reason to use the graph anyway, we stick with a simpler approach in + selection, and use the graph only for propagating default + implementations. + +Trait impl selection can succeed even when multiple impls can apply, +as long as they are part of the same specialization family. In that +case, it returns a *single* impl on success -- this is the most +specialized impl *known* to apply. However, if there are any inference +variables in play, the returned impl may not be the actual impl we +will use at trans time. Thus, we take special care to avoid projecting +associated types unless either (1) the associated type does not use +`default` and thus cannot be overridden or (2) all input types are +known concretely. diff --git a/src/librustc/middle/traits/specialize.rs b/src/librustc/middle/traits/specialize.rs index 0f47e19eaf3f4426aad7c09c0b396a15dcfe3f0f..30897e9289d9bca17ca9ad00a220204cfc0aa88e 100644 --- a/src/librustc/middle/traits/specialize.rs +++ b/src/librustc/middle/traits/specialize.rs @@ -13,6 +13,9 @@ // // At the moment, this implementation support only the simple "chain" rule: // If any two impls overlap, one must be a strict subset of the other. +// +// See traits/README.md for a bit more detail on how specialization +// fits together with the rest of the trait machinery. use super::util; use super::SelectionContext;