| A type, const or lifetime parameter that is specified for `impl` is not |
| constrained. |
| |
| Erroneous code example: |
| |
| ```compile_fail,E0207 |
| struct Foo; |
| |
| impl<T: Default> Foo { |
| // error: the type parameter `T` is not constrained by the impl trait, self |
| // type, or predicates [E0207] |
| fn get(&self) -> T { |
| <T as Default>::default() |
| } |
| } |
| ``` |
| |
| Any type or const parameter of an `impl` must meet at least one of the |
| following criteria: |
| |
| - it appears in the _implementing type_ of the impl, e.g. `impl<T> Foo<T>` |
| - for a trait impl, it appears in the _implemented trait_, e.g. |
| `impl<T> SomeTrait<T> for Foo` |
| - it is bound as an associated type, e.g. `impl<T, U> SomeTrait for T |
| where T: AnotherTrait<AssocType=U>` |
| |
| Any unconstrained lifetime parameter of an `impl` is not supported if the |
| lifetime parameter is used by an associated type. |
| |
| ### Error example 1 |
| |
| Suppose we have a struct `Foo` and we would like to define some methods for it. |
| The previous code example has a definition which leads to a compiler error: |
| |
| The problem is that the parameter `T` does not appear in the implementing type |
| (`Foo`) of the impl. In this case, we can fix the error by moving the type |
| parameter from the `impl` to the method `get`: |
| |
| ``` |
| struct Foo; |
| |
| // Move the type parameter from the impl to the method |
| impl Foo { |
| fn get<T: Default>(&self) -> T { |
| <T as Default>::default() |
| } |
| } |
| ``` |
| |
| ### Error example 2 |
| |
| As another example, suppose we have a `Maker` trait and want to establish a |
| type `FooMaker` that makes `Foo`s: |
| |
| ```compile_fail,E0207 |
| trait Maker { |
| type Item; |
| fn make(&mut self) -> Self::Item; |
| } |
| |
| struct Foo<T> { |
| foo: T |
| } |
| |
| struct FooMaker; |
| |
| impl<T: Default> Maker for FooMaker { |
| // error: the type parameter `T` is not constrained by the impl trait, self |
| // type, or predicates [E0207] |
| type Item = Foo<T>; |
| |
| fn make(&mut self) -> Foo<T> { |
| Foo { foo: <T as Default>::default() } |
| } |
| } |
| ``` |
| |
| This fails to compile because `T` does not appear in the trait or in the |
| implementing type. |
| |
| One way to work around this is to introduce a phantom type parameter into |
| `FooMaker`, like so: |
| |
| ``` |
| use std::marker::PhantomData; |
| |
| trait Maker { |
| type Item; |
| fn make(&mut self) -> Self::Item; |
| } |
| |
| struct Foo<T> { |
| foo: T |
| } |
| |
| // Add a type parameter to `FooMaker` |
| struct FooMaker<T> { |
| phantom: PhantomData<T>, |
| } |
| |
| impl<T: Default> Maker for FooMaker<T> { |
| type Item = Foo<T>; |
| |
| fn make(&mut self) -> Foo<T> { |
| Foo { |
| foo: <T as Default>::default(), |
| } |
| } |
| } |
| ``` |
| |
| Another way is to do away with the associated type in `Maker` and use an input |
| type parameter instead: |
| |
| ``` |
| // Use a type parameter instead of an associated type here |
| trait Maker<Item> { |
| fn make(&mut self) -> Item; |
| } |
| |
| struct Foo<T> { |
| foo: T |
| } |
| |
| struct FooMaker; |
| |
| impl<T: Default> Maker<Foo<T>> for FooMaker { |
| fn make(&mut self) -> Foo<T> { |
| Foo { foo: <T as Default>::default() } |
| } |
| } |
| ``` |
| |
| ### Error example 3 |
| |
| Suppose we have a struct `Foo` and we would like to define some methods for it. |
| The following code example has a definition which leads to a compiler error: |
| |
| ```compile_fail,E0207 |
| struct Foo; |
| |
| impl<const T: i32> Foo { |
| // error: the const parameter `T` is not constrained by the impl trait, self |
| // type, or predicates [E0207] |
| fn get(&self) -> i32 { |
| i32::default() |
| } |
| } |
| ``` |
| |
| The problem is that the const parameter `T` does not appear in the implementing |
| type (`Foo`) of the impl. In this case, we can fix the error by moving the type |
| parameter from the `impl` to the method `get`: |
| |
| |
| ``` |
| struct Foo; |
| |
| // Move the const parameter from the impl to the method |
| impl Foo { |
| fn get<const T: i32>(&self) -> i32 { |
| i32::default() |
| } |
| } |
| ``` |
| |
| ### Error example 4 |
| |
| Suppose we have a struct `Foo` and a struct `Bar` that uses lifetime `'a`. We |
| would like to implement trait `Contains` for `Foo`. The trait `Contains` have |
| the associated type `B`. The following code example has a definition which |
| leads to a compiler error: |
| |
| ```compile_fail,E0207 |
| struct Foo; |
| struct Bar<'a>; |
| |
| trait Contains { |
| type B; |
| |
| fn get(&self) -> i32; |
| } |
| |
| impl<'a> Contains for Foo { |
| type B = Bar<'a>; |
| |
| // error: the lifetime parameter `'a` is not constrained by the impl trait, |
| // self type, or predicates [E0207] |
| fn get(&self) -> i32 { |
| i32::default() |
| } |
| } |
| ``` |
| |
| Please note that unconstrained lifetime parameters are not supported if they are |
| being used by an associated type. |
| |
| In cases where the associated type's lifetime is meant to be tied to the |
| self type, and none of the methods on the trait need ownership or different |
| mutability, then an option is to implement the trait on a borrowed type: |
| |
| ```rust |
| struct Foo(i32); |
| |
| trait Contents { |
| type Item; |
| |
| fn get(&self) -> Self::Item; |
| } |
| |
| // Note the lifetime `'a` is used both for the self type... |
| impl<'a> Contents for &'a Foo { |
| // ...and the associated type. |
| type Item = &'a i32; |
| |
| fn get(&self) -> Self::Item { |
| &self.0 |
| } |
| } |
| ``` |
| |
| ### Additional information |
| |
| For more information, please see [RFC 447]. |
| |
| [RFC 447]: https://github.com/rust-lang/rfcs/blob/master/text/0447-no-unused-impl-parameters.md |