Skip to content

Commit 1209054

Browse files
committed
rfc, associated-default-groups: add unresolved questions.
1 parent a1c2077 commit 1209054

File tree

1 file changed

+104
-1
lines changed

1 file changed

+104
-1
lines changed

text/0000-assoc-default-groups.md

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,110 @@ There are a few interesting things to note here:
824824
# Unresolved questions
825825
[unresolved-questions]: #unresolved-questions
826826

827-
There are none.
827+
## 1. When do suitability of defaults need to be proven?
828+
829+
Consider a trait `Foo<T>` defined as:
830+
831+
```rust
832+
trait Foo<T> {
833+
type Bar: Clone = Vec<T>;
834+
}
835+
```
836+
837+
Let's also assume the following implementation of `Clone`:
838+
839+
```rust
840+
impl<T: Clone> Clone for Vec<T> { ... }
841+
```
842+
843+
To prove that `Vec<T>: Clone`, we must prove that `T: Clone`.
844+
However, `Foo<T>` does not say that `T: Clone` so is its definition valid?
845+
If the suitability of `Vec<T>` is checked where `Foo<T>` is defined (1),
846+
then we don't know that `T: Clone` and so the definition must be rejected.
847+
To make the compiler admit `Foo<T>`, we would have to write:
848+
849+
```rust
850+
trait Foo<T: Clone> {
851+
type Bar: Clone = Vec<T>;
852+
}
853+
```
854+
855+
Now it is provable that `T: Clone` so `Vec<T>: Clone` which is what was required.
856+
857+
If instead the suitability of defaults are checked in `impl`ementations (2),
858+
then proving `Vec<T>: Clone` would not be required in `Foo<T>`'s definition and
859+
so then `Foo<T>` would type-check. As a result, it would be admissible to write:
860+
861+
```rust
862+
#[derive(Copy, Clone)]
863+
struct A;
864+
865+
struct B;
866+
867+
impl Foo<A> for B {}
868+
```
869+
870+
since `Vec<A>: Clone` holds.
871+
872+
With condition (2), strictly more programs are accepted than with (1).
873+
It may be that useful programs are rejected if we enforce (1) rather than (2).
874+
However, it would also be the more conservative choice, allowing us to move
875+
towards (2) when necessary. As it is currently unclear what solution is best,
876+
this question is left unresolved.
877+
878+
## 1. Where are cycles checked?
879+
880+
[playground]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=e823eea5e7ecba5da78cff225e0adaf9
881+
882+
Consider a program *([playground])*:
883+
884+
```rust
885+
#![feature(associated_type_defaults)]
886+
887+
trait A {
888+
type B = Self::C; // B defaults to C,
889+
type C = Self::B; // C defaults to B, and we have a cycle!
890+
}
891+
892+
impl A for () {}
893+
894+
fn _foo() {
895+
let _x: <() as A>::B;
896+
}
897+
898+
// Removing this function will make the example compile.
899+
fn main() {
900+
let _x: <() as A>::B;
901+
}
902+
```
903+
904+
Currently, this results in a crash. This will need to be fixed.
905+
At the very latest, `impl A for () {}` should have been an error.
906+
907+
```rust
908+
trait A {
909+
type B = Self::C;
910+
type C = Self::B;
911+
}
912+
913+
impl A for () {} // This OK but shouldn't be.
914+
```
915+
916+
If cycles are checked for in `impl A for ()`, then it would be valid to write:
917+
918+
```rust
919+
trait A {
920+
type B = Self::C;
921+
type C = Self::B;
922+
}
923+
924+
impl A for () {
925+
type B = u8; // The cycle is broken!
926+
}
927+
```
928+
929+
Alternatively, cycles could be checked for in `A`'s definition.
930+
This is similar to the previous question in (1).
828931

829932
# Future possibilities
830933
[future-possibilities]: #future-possibilities

0 commit comments

Comments
 (0)