Skip to content

Commit 7d78436

Browse files
author
Nick Hamann
committed
Improve the long explanation of E0207.
The previous explanation does not seem to explain what it means for an implementation parameter to be used or unused. The new explanation lists the three ways specific ways by which an impl parameter becomes constrained (taken from RFC 447). This also adds a link to RFC 447. The explanation has two different examples. The first is adapted from RFC 447, and shows an instance of E0207 on a impl for a type. The second one is a trait impl example adapted from issue #22834. Closes #33650
1 parent cde0fa5 commit 7d78436

File tree

1 file changed

+111
-15
lines changed

1 file changed

+111
-15
lines changed

src/librustc_typeck/diagnostics.rs

Lines changed: 111 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2387,39 +2387,135 @@ impl Copy for &'static Bar { } // error
23872387
"##,
23882388

23892389
E0207: r##"
2390-
You declared an unused type parameter when implementing a trait on an object.
2391-
Erroneous code example:
2390+
Any type parameter or lifetime parameter of an `impl` must meet at least one of
2391+
the following criteria:
2392+
2393+
- it appears in the self type of the impl
2394+
- for a trait impl, it appears in the trait reference
2395+
- it is bound as an associated type
2396+
2397+
### Error example 1
2398+
2399+
Suppose we have a struct `Foo` and we would like to define some methods for it.
2400+
The following definition leads to a compiler error:
23922401
23932402
```compile_fail
2394-
trait MyTrait {
2395-
fn get(&self) -> usize;
2403+
struct Foo;
2404+
2405+
impl<T: Default> Foo {
2406+
// error: the type parameter `T` is not constrained by the impl trait, self
2407+
// type, or predicates [E0207]
2408+
fn get(&self) -> T {
2409+
<T as Default>::default()
2410+
}
23962411
}
2412+
```
2413+
2414+
The problem is that the parameter `T` does not appear in the self type (`Foo`)
2415+
of the impl. In this case, we can fix the error by moving the type parameter
2416+
from the `impl` to the method `get`:
2417+
23972418
2419+
```
23982420
struct Foo;
23992421
2400-
impl<T> MyTrait for Foo {
2401-
fn get(&self) -> usize {
2402-
0
2422+
// Move the type parameter from the impl to the method
2423+
impl Foo {
2424+
fn get<T: Default>(&self) -> T {
2425+
<T as Default>::default()
24032426
}
24042427
}
24052428
```
24062429
2407-
Please check your object definition and remove unused type
2408-
parameter(s). Example:
2430+
### Error example 2
24092431
2432+
As another example, suppose we have a `Maker` trait and want to establish a
2433+
type `FooMaker` that makes `Foo`s:
2434+
2435+
```compile_fail
2436+
trait Maker {
2437+
type Item;
2438+
fn make(&mut self) -> Self::Item;
2439+
}
2440+
2441+
struct Foo<T> {
2442+
foo: T
2443+
}
2444+
2445+
struct FooMaker;
2446+
2447+
impl<T: Default> Maker for FooMaker {
2448+
// error: the type parameter `T` is not constrained by the impl trait, self
2449+
// type, or predicates [E0207]
2450+
type Item = Foo<T>;
2451+
2452+
fn make(&mut self) -> Foo<T> {
2453+
Foo { foo: <T as Default>::default() }
2454+
}
2455+
}
24102456
```
2411-
trait MyTrait {
2412-
fn get(&self) -> usize;
2457+
2458+
This fails to compile because `T` does not appear in the trait or in the
2459+
implementing type.
2460+
2461+
One way to work around this is to introduce a phantom type parameter into
2462+
`FooMaker`, like so:
2463+
2464+
```
2465+
use std::marker::PhantomData;
2466+
2467+
trait Maker {
2468+
type Item;
2469+
fn make(&mut self) -> Self::Item;
24132470
}
24142471
2415-
struct Foo;
2472+
struct Foo<T> {
2473+
foo: T
2474+
}
24162475
2417-
impl MyTrait for Foo {
2418-
fn get(&self) -> usize {
2419-
0
2476+
// Add a type parameter to `FooMaker`
2477+
struct FooMaker<T> {
2478+
phantom: PhantomData<T>,
2479+
}
2480+
2481+
impl<T: Default> Maker for FooMaker<T> {
2482+
type Item = Foo<T>;
2483+
2484+
fn make(&mut self) -> Foo<T> {
2485+
Foo {
2486+
foo: <T as Default>::default(),
2487+
}
2488+
}
2489+
}
2490+
```
2491+
2492+
Another way is to do away with the associated type in `Maker` and use an input
2493+
type parameter instead:
2494+
2495+
```
2496+
// Use a type parameter instead of an associated type here
2497+
trait Maker<Item> {
2498+
fn make(&mut self) -> Item;
2499+
}
2500+
2501+
struct Foo<T> {
2502+
foo: T
2503+
}
2504+
2505+
struct FooMaker;
2506+
2507+
impl<T: Default> Maker<Foo<T>> for FooMaker {
2508+
fn make(&mut self) -> Foo<T> {
2509+
Foo { foo: <T as Default>::default() }
24202510
}
24212511
}
24222512
```
2513+
2514+
### Additional information
2515+
2516+
For more information, please see [RFC 447].
2517+
2518+
[RFC 447]: https://github.com/rust-lang/rfcs/blob/master/text/0447-no-unused-impl-parameters.md
24232519
"##,
24242520

24252521
E0210: r##"

0 commit comments

Comments
 (0)