Skip to content

Commit 37b7eff

Browse files
committed
Moved coherence and orphan rules to a separate file, and updated to match RFC#2451
1 parent 4b21b64 commit 37b7eff

File tree

3 files changed

+82
-24
lines changed

3 files changed

+82
-24
lines changed

src/items/coherence.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
## What is coherence and why do we care?
2+
3+
Coherence means that for any given trait and type, there is one specific
4+
implementation that applies. This is important for Rust to be easy to reason
5+
about. When you write `<Foo as Bar>::trait_method`, the compiler needs to know
6+
what actual implementation to use.
7+
8+
In languages without coherence, the compiler has to have some way to choose
9+
which implementation to use when multiple implementations could apply. Scala
10+
does this by having complex scope resolution rules for "implicit" parameters.
11+
Haskell (when a discouraged flag is enabled) does this by picking an impl
12+
arbitrarily.
13+
14+
Rust's solution is to enforce that there is only one impl to choose from at all.
15+
While the rules required to enforce this are quite complex, the result is easy
16+
to reason about, and is generally considered to be quite important for Rust.
17+
New features like specialization allow more than one impl to apply, but for any
18+
given type and trait, there will always be exactly one which is most specific,
19+
and deterministically be chosen.
20+
21+
An important piece of enforcing coherence is restricting "orphan impls". An impl
22+
is orphaned if it is implementing a trait you don't own for a type you don't
23+
own. Rust's rules around this balance two separate, but related goals:
24+
25+
- Ensuring that two crates can't write impls that would overlap (e.g. no crate
26+
other than `std` can write `impl From<usize> for Vec<i32>`. If they could,
27+
your program might stop compiling just by using two crates with an overlapping
28+
impl).
29+
- Restricting the impls that can be written so crates can add implementations
30+
for traits/types they do own without worrying about breaking downstream
31+
crates.
32+
33+
34+
## Definitions
35+
36+
Local Trait: A trait which was defined in the current crate. Whether a trait is
37+
local or not has nothing to do with type parameters. Given `trait Foo<T, U>`,
38+
`Foo` is always local, regardless of the types used for `T` or `U`.
39+
40+
Local Type: A struct, enum, or union which was defined in the current crate.
41+
This is not affected by type parameters. `struct Foo` is considered local, but
42+
`Vec<Foo>` is not. `LocalType<ForeignType>` is local. Type aliases and trait
43+
aliases do not affect locality.
44+
45+
Covered Type: A type which appears as a parameter to another type. For example,
46+
`T` is uncovered, but the `T` in `Vec<T>` is covered. This is only relevant for
47+
type parameters.
48+
49+
Blanket Impl: Any implementation where a type appears uncovered. `impl<T> Foo
50+
for T`, `impl<T> Bar<T> for T`, `impl<T> Bar<Vec<T>> for T`, and `impl<T> Bar<T>
51+
for Vec<T>` are considered blanket impls. However, `impl<T> Bar<Vec<T>> for
52+
Vec<T>` is not a blanket impl, as all instances of `T` which appear in this impl
53+
are covered by `Vec`.
54+
55+
Fundamental Type: A type for which you cannot add a blanket impl backwards
56+
compatibly. This includes `&`, `&mut`, and `Box`. Any time a type `T` is
57+
considered local, `&T`, `&mut T`, and `Box<T>` are also considered local.
58+
Fundamental types cannot cover other types. Any time the term "covered type" is
59+
used, the `T` in `&T`, `&mut T`, and `Box<T>` is not considered covered.
60+
61+
62+
## Concrete orphan rules
63+
64+
Assumes the same definitions [as above](#definitions).
65+
66+
Given `impl<P1..=Pn> Trait<T1..=Tn> for T0`, an impl is valid only if at
67+
least one of the following is true:
68+
69+
- `Trait` is a local trait
70+
- All of
71+
- At least one of the types `T0..=Tn` must be a local type. Let `Ti` be the
72+
first such type.
73+
- No uncovered type parameters `P1..=Pn` may appear in `T0..Ti` (excluding
74+
`Ti`)
75+
76+
We only restrict the appearance of *uncovered* type parameters. Once again, it is
77+
important to note that for the purposes of coherence, `#[fundamental]` types are
78+
special. The `T` in `Box<T>` is not considered covered, and `Box<LocalType>`
79+
is considered local.

src/items/implementations.md

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -152,29 +152,7 @@ impl Shape for Circle {
152152

153153
### Trait Implementation Coherence
154154

155-
A trait implementation is considered incoherent if either the orphan check fails
156-
or there are overlapping implementation instances.
157-
158-
Two trait implementations overlap when there is a non-empty intersection of the
159-
traits the implementation is for, the implementations can be instantiated with
160-
the same type. <!-- This is probably wrong? Source: No two implementations can
161-
be instantiable with the same set of types for the input type parameters. -->
162-
163-
The `Orphan Check` states that every trait implementation must meet either of
164-
the following conditions:
165-
166-
1. The trait being implemented is defined in the same crate.
167-
168-
2. At least one of either `Self` or a generic type parameter of the trait must
169-
meet the following grammar, where `C` is a nominal type defined
170-
within the containing crate:
171-
172-
```ignore
173-
T = C
174-
| &C
175-
| &mut C
176-
| Box<C>
177-
```
155+
A trait implementation must follow the [coherence] rules.
178156

179157
## Generic Implementations
180158

@@ -224,3 +202,4 @@ attributes].
224202
[path]: ../paths.md
225203
[the lint check attributes]: ../attributes/diagnostics.md#lint-check-attributes
226204
[Unsafe traits]: traits.md#unsafe-traits
205+
[coherence]: coherence.md

src/special-types-and-traits.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ compiler, not by [implementation items].
170170
[Methods]: items/associated-items.md#associated-functions-and-methods
171171
[method resolution]: expressions/method-call-expr.md
172172
[operators]: expressions/operator-expr.md
173-
[orphan rules]: items/implementations.md#trait-implementation-coherence
173+
[orphan rules]: items/coherence.md
174174
[Raw pointers]: types/pointer.md#raw-pointers-const-and-mut
175175
[`static` items]: items/static-items.md
176176
[Shared references]: types/pointer.md#shared-references-

0 commit comments

Comments
 (0)