diff --git a/src/traits/wf.md b/src/traits/wf.md index cd0fb556..bd1188d8 100644 --- a/src/traits/wf.md +++ b/src/traits/wf.md @@ -73,7 +73,9 @@ struct OnlyClone where T: Clone { } // The only types appearing are type parameters: we have nothing to check, // the type definition is well-formed. +``` +```rust,ignore struct Foo where T: Clone { foo: OnlyClone, } @@ -87,23 +89,28 @@ struct Foo where T: Clone { // } // ``` // which is provable. +``` -struct Bar where OnlyClone: Debug { +```rust,ignore +struct Bar where ::Item: Debug { bar: i32, } -// The only non-parameter type which appears in this definition is -// `OnlyClone`. The generated goal is the following: +// The only non-parameter types which appear in this definition are +// `::Item` and `i32`. The generated goal is the following: // ``` // forall { -// if (FromEnv(OnlyClone: Debug)) { -// WellFormed(OnlyClone) +// if (FromEnv(::Item: Debug)) { +// WellFormed(::Item) && +// WellFormed(i32) // } // } // ``` -// which is not provable since `WellFormed(OnlyClone)` requires proving -// `Implemented(T: Clone)`, and we are unable to prove that for an unknown `T`. +// which is not provable since `WellFormed(::Item)` requires +// proving `Implemented(T: Iterator)`, and we are unable to prove that for an +// unknown `T`. +// // Hence, this type definition is considered illegal. An additional -// `where T: Clone` would make it legal. +// `where T: Iterator` would make it legal. ``` # Trait definitions @@ -137,41 +144,47 @@ under the assumption that the different where clauses hold. Some examples: ```rust,ignore -struct OnlyClone { ... } - -trait Foo where T: Clone, OnlyClone: Debug { +trait Foo where T: Iterator, ::Item: Debug { ... } // The only non-parameter type which appears in this definition is -// `OnlyClone`. The generated goal is the following: +// `::Item`. The generated goal is the following: // ``` // forall { -// if (FromEnv(T: Clone), FromEnv(OnlyClone: Debug)) { -// WellFormed(OnlyClone) +// if (FromEnv(T: Iterator), FromEnv(::Item: Debug)) { +// WellFormed(::Item) // } // } // ``` -// which is provable thanks to the `FromEnv(T: Clone)` assumption. +// which is provable thanks to the `FromEnv(T: Iterator)` assumption. +``` +```rust,ignore trait Bar { - type Assoc: From>; + type Assoc: From<::Item>; } // The only non-parameter type which appears in this definition is -// `OnlyClone`. The generated goal is the following: +// `::Item`. The generated goal is the following: +// ``` // forall { -// WellFormed(OnlyClone) +// WellFormed(::Item) // } +// ``` // which is not provable, hence the trait definition is considered illegal. +``` +```rust,ignore trait Baz { - type Assoc: From> where T: Clone; + type Assoc: From<::Item> where T: Iterator; } // The generated goal is now: +// ``` // forall { -// if (FromEnv(T: Clone)) { -// WellFormed(OnlyClone) +// if (FromEnv(T: Iterator)) { +// WellFormed(::Item) // } // } +// ``` // which is now provable. ``` @@ -267,3 +280,161 @@ we allow the use of implied bounds on associated types: if we have chapter indicates that we are able to deduce `FromEnv(::Assoc: Bounds_assoc)` without knowing what the precise value of `::Assoc` is. + +Some examples for the generated goal: +```rust,ignore +trait Copy { } +// `WellFormed(Self: Copy) :- Implemented(Self: Copy).` + +trait Partial where Self: Copy { } +// ``` +// WellFormed(Self: Partial) :- +// Implemented(Self: Partial) && +// WellFormed(Self: Copy). +// ``` + +trait Complete where Self: Partial { } +// ``` +// WellFormed(Self: Complete) :- +// Implemented(Self: Complete) && +// WellFormed(Self: Partial). +// ``` + +impl Partial for T where T: Complete { } +// The generated goal is: +// ``` +// forall { +// if (FromEnv(T: Complete)) { +// WellFormed(T: Partial) +// } +// } +// ``` +// Then proving `WellFormed(T: Partial)` amounts to proving +// `Implemented(T: Partial)` and `Implemented(T: Copy)`. +// Both those facts can be deduced from the `FromEnv(T: Complete)` in our +// environment: this impl is legal. + +impl Complete for T { } +// The generated goal is: +// ``` +// forall { +// WellFormed(T: Complete) +// } +// ``` +// Then proving `WellFormed(T: Complete)` amounts to proving +// `Implemented(T: Complete)`, `Implemented(T: Partial)` and +// `Implemented(T: Copy)`. +// +// `Implemented(T: Complete)` can be proved thanks to the +// `impl Complete for T` blanket impl. +// +// `Implemented(T: Partial)` can be proved thanks to the +// `impl Partial for T where T: Complete` impl and because we know +// `T: Complete` holds. + +// However, `Implemented(T: Copy)` cannot be proved: the impl is illegal. +// An additional `where T: Copy` bound would be sufficient to make that impl +// legal. +``` + +```rust,ignore +trait Bar { } + +impl Bar for T where ::Item: Bar { } +// We have a non-parameter type appearing in the where clauses: +// `::Item`. The generated goal is: +// ``` +// forall { +// if (FromEnv(::Item: Bar)) { +// WellFormed(T: Bar) && +// WellFormed(::Item: Bar) +// } +// } +// ``` +// And `WellFormed(::Item: Bar)` is not provable: we'd need +// an additional `where T: Iterator` for example. +``` + +```rust,ignore +trait Foo { } + +trait Bar { + type Item: Foo; +} + +struct Stuff { } + +impl Bar for Stuff where T: Foo { + type Item = T; +} +// The generated goal is: +// ``` +// forall { +// if (FromEnv(T: Foo)) { +// WellFormed(T: Foo). +// } +// } +// ``` +// which is provable. +``` + +```rust,ignore +trait Debug { ... } +// `WellFormed(Self: Debug) :- Implemented(Self: Debug).` + +struct Box { ... } +impl Debug for Box where T: Debug { ... } + +trait PointerFamily { + type Pointer: Debug where T: Debug; +} +// `WellFormed(Self: PointerFamily) :- Implemented(Self: PointerFamily).` + +struct BoxFamily; + +impl PointerFamily for CowFamily { + type Pointer = Box where T: Debug; +} +// The generated goal is: +// ``` +// forall { +// WellFormed(CowFamily: PointerFamily) && +// +// if (FromEnv(T: Debug)) { +// WellFormed(Box: Debug) && +// WellFormed(Box) +// } +// } +// ``` +// `WellFormed(CowFamily: PointerFamily)` amounts to proving +// `Implemented(CowFamily: PointerFamily)`, which is ok thanks to our impl. +// +// `WellFormed(Box)` is always true (there are no where clauses on the +// `Box` type definition). +// +// Moreover, we have an `impl Debug for Box`, hence +// we can prove `WellFormed(Box: Debug)` and the impl is indeed legal. +``` + +```rust,ignore +trait Foo { + type Assoc; +} + +struct OnlyClone { ... } + +impl Foo for i32 { + type Assoc = OnlyClone; +} +// The generated goal is: +// ``` +// forall { +// WellFormed(i32: Foo) && +// WellFormed(OnlyClone) +// } +// ``` +// however `WellFormed(OnlyClone)` is not provable because it requires +// `Implemented(T: Clone)`. It would be tempting to just add a `where T: Clone` +// bound inside the `impl Foo for i32` block, however we saw that it was +// illegal to add where clauses that didn't come from the trait definition. +```