Skip to content

Commit

Permalink
merge piece on overlap checks with docs about coherence (based on rev…
Browse files Browse the repository at this point in the history
…iew comments)
  • Loading branch information
jdonszelmann committed Aug 13, 2024
1 parent a29b0ae commit 8fc6554
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@
- [Caching subtleties](./traits/caching.md)
- [Implied bounds](./traits/implied-bounds.md)
- [Specialization](./traits/specialization.md)
- [Overlap checks](./traits/overlap.md)
- [Chalk-based trait solving](./traits/chalk.md)
- [Lowering to logic](./traits/lowering-to-logic.md)
- [Goals and clauses](./traits/goals-and-clauses.md)
Expand All @@ -157,6 +156,7 @@
- [Type checking](./type-checking.md)
- [Method Lookup](./method-lookup.md)
- [Variance](./variance.md)
- [Coherence Checking](./coherence.md)
- [Opaque Types](./opaque-types-type-alias-impl-trait.md)
- [Inference details](./opaque-types-impl-trait-inference.md)
- [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md)
Expand Down
49 changes: 37 additions & 12 deletions src/traits/overlap.md → src/coherence.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
# Overlap checks

As part of checking items (specifically: structs, enums, traits, unions),
the compiler checks whether impl blocks overlap, for example because they define the same functions.
This is an example an overlap check.
The same overlap check is done when constructing a [specialization graph](./specialization.md).
Here, trait implementations could overlap, for example because of a conflicting blanket implementation overlapping with some specific implementation.
# Coherence

The overlap check always compares two impls.
In the case of inherent impl blocks, this means that at least for small n,
rustc quite literally compares each impl to each other impl block in an `n^2` loop
(see `fn check_item` in coherence/inherent_impls_overlap.rs).
> NOTE: this is based on [notes by @lcnr](https://github.com/rust-lang/rust/pull/121848)
Coherence checking is what detects both of trait impls and inherent impls overlapping with others.
(reminder: [inherent impls](https://doc.rust-lang.org/reference/items/implementations.html#inherent-implementations) are impls of concrete types like `impl MyStruct {}`)

Overlapping trait impls always produce an error,
while overlapping inherent impls result in an error only if they have methods with the same name.

Checking for overlaps is split in two parts. First there's the [overlap check(s)](#overlap-checks),
which finds overlaps between traits and inherent implementations that the compiler currently knows about.

However, Coherence also results in an error if any other impls **could** exist,
even if they are currently unknown.
This affects impls which may get added to upstream crates in a backwards compatible way,
and impls from downstream crates.
This is called the Orphan check.

## Overlap checks

Overlap checks are performed for both inherent impls, and for trait impls.
This uses the same overlap checking code, really done as two separate analyses.
Overlap checks always consider pairs of implementations, comparing them to each other.

Overlap checking for inherent impl blocks is done through `fn check_item` in coherence/inherent_impls_overlap.rs),
where you can very clearly see that (at least for small `n`), the check really performs `n^2`
comparisons between impls.

In the case of traits, this check is currently done as part of building the [specialization graph](./specialization.md),
to handle specializing impls overlapping with their parent, but this may change in the future.

In both cases, all pairs of impls are checked for overlap.

Overlapping is sometimes partially allowed:

1. for maker traits
2. under [specialization](./specialization.md)

Expand All @@ -23,7 +46,7 @@ Both try to apply negative reasoning to prove that an overlap is definitely impo

[`OverlapMode`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/traits/specialization_graph/enum.OverlapMode.html

## The explicit negative impl check
### The explicit negative impl check

This check is done in [`impl_intersection_has_negative_obligation`].

Expand All @@ -50,7 +73,7 @@ This is not currently stable.

[`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

## The implicit negative impl check
### The implicit negative impl check

This check is done in [`impl_intersection_has_impossible_obligation`],
and does not rely on negative trait implementations and is stable.
Expand All @@ -70,3 +93,5 @@ Importantly, this works even if there isn't a `impl !Error for MyLocalType`.

[`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



2 changes: 1 addition & 1 deletion src/solve/invariants.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ in the trait solver

#### The type system is complete during the implicit negative overlap check in coherence ✅

For more on overlap checking: [./overlap.md]
For more on overlap checking: [../coherence.md]

During the implicit negative overlap check in coherence we must never return *error* for
goals which can be proven. This would allow for overlapping impls with potentially different
Expand Down
2 changes: 1 addition & 1 deletion src/traits/specialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Defined in the `specialize` module.

The basic strategy is to build up a *specialization graph* during
coherence checking (coherence checking looks for [overlapping impls](./overlap.md)).
coherence checking (coherence checking looks for [overlapping impls](../coherence.md)).
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
Expand Down

0 comments on commit 8fc6554

Please sign in to comment.