|
| 1 | +# Overlap checks |
| 2 | + |
| 3 | +As part of checking items (specifically: structs, enums, traits, unions), |
| 4 | +the compiler checks whether its impl blocks overlap, for example because they define the same functions. |
| 5 | +This is an example an overlap check. |
| 6 | +The same overlap check is done when constructing a [specialization graph](./specialization.md). |
| 7 | +Here, traits implementations could overlap because of a conflicting blanket implementation overlapping with some specific implementation. |
| 8 | + |
| 9 | +The overlap check always compares two impls. |
| 10 | +In the case of inherent impl blocks, this means that for small n, |
| 11 | +rustc quite literally compares each impl to each other impl block in an n^2 loop |
| 12 | +(see `fn check_item` in coherence/inherent_impls_overlap.rs). |
| 13 | + |
| 14 | +Overlapping is sometimes partially allowed: |
| 15 | +1. for maker traits |
| 16 | +2. under [specialization](./specialization.md) |
| 17 | + |
| 18 | +but normally isn't. |
| 19 | + |
| 20 | +The overlap check has various modes (see [`OverlapMode`]). |
| 21 | +Importantly, there's the explicit negative impl check, and the implicit negative impl check. |
| 22 | +Both try to apply negative reasoning to prove that an overlap is definitely impossible. |
| 23 | + |
| 24 | +[`OverlapMode`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/traits/specialization_graph/enum.OverlapMode.html |
| 25 | + |
| 26 | +## The explicit negative impl check |
| 27 | + |
| 28 | +This check is done in [`impl_intersection_has_negative_obligation`]. |
| 29 | + |
| 30 | +This check tries to find a negative trait implementation. |
| 31 | +For example: |
| 32 | + |
| 33 | +```rust |
| 34 | +struct MyCustomBox<T: ?Sized>(Box<T>) |
| 35 | + |
| 36 | +// both in your own crate |
| 37 | +impl From<&str> for MyCustomBox<dyn Error> {} |
| 38 | +impl<E> From<E> for MyCustomBox<dyn Error> where E: Error {} |
| 39 | +``` |
| 40 | + |
| 41 | +In this example, we'd get: |
| 42 | +`MyCustomBox<dyn Error>: From<&str>` and `MyCustomBox<dyn Error>: From<?E>`, giving `?E = &str`. |
| 43 | + |
| 44 | +And thus, these two implementations would overlap. |
| 45 | +However, libstd provides `&str: !Error`, and therefore guarantees that there |
| 46 | +will never be a positive implementation of `&str: Error`, and thus there is no overlap. |
| 47 | + |
| 48 | +Note that for this kind of negative impl check, we must have explicit negative implementations provided. |
| 49 | +This is not currently stable. |
| 50 | + |
| 51 | +[`impl_intersection_has_negative_obligation`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_trait_selection/traits/coherence/fn.impl_intersection_has_impossible_obligation.htmlhttps://doc.rust-lang.org/beta/nightly-rustc/rustc_trait_selection/traits/coherence/fn.impl_intersection_has_negative_obligation.html |
| 52 | + |
| 53 | +## The implicit negative impl check |
| 54 | + |
| 55 | +This check is done in [`impl_intersection_has_impossible_obligation`], |
| 56 | +and does not rely on negative trait implementations and is stable. |
| 57 | + |
| 58 | +Let's say there's a |
| 59 | +```rust |
| 60 | +impl From<MyLocalType> for Box<dyn Error> {} // in your own crate |
| 61 | +impl<E> From<E> for Box<dyn Error> where E: Error {} // in std |
| 62 | +``` |
| 63 | + |
| 64 | +This would give: `Box<dyn Error>: From<MyLocalType>`, and `Box<dyn Error>: From<?E>`, |
| 65 | +giving `?E = MyLocalType`. |
| 66 | + |
| 67 | +In your crate there's no `MyLocalType: Error`, downstream crates cannot implement `Error` (a remote trait) for `MyLocalType` (a remote type). |
| 68 | +Therefore, these two impls do not overlap. |
| 69 | +Importantly, this works even if there isn't a `impl !Error for MyLocalType`. |
| 70 | + |
| 71 | +[`impl_intersection_has_impossible_obligation`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_trait_selection/traits/coherence/fn.impl_intersection_has_impossible_obligation.html |
| 72 | + |
0 commit comments