Skip to content

E0283 doesn't always tell you to replace ("specify") generic parameters #128585

@QuineDot

Description

@QuineDot

Code

use std::num::NonZero;
trait Trait {}
impl<T: ?Sized + Trait> Trait for &mut T {}
impl Trait for [u8] {}
impl Trait for [NonZero<u8>] {}

fn expect<B: Trait>(_: B) {}

fn test(slice: &mut [u32]) {
    // Doesn't tell you to replace `B`
    expect(bytemuck::cast_slice_mut(slice));

    // Does tell you to replace `B`
    // let cast = bytemuck::cast_slice_mut(slice);
    // expect(cast);
}

Current output

error[E0283]: type annotations needed
   --> src/lib.rs:11:12
    |
11  |     expect(bytemuck::cast_slice_mut(slice));
    |            ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `B` declared on the function `cast_slice_mut`
    |
    = note: cannot satisfy `_: NoUninit`
    = help: the following types implement trait `NoUninit`:
              NonZero<i128>
              NonZero<i16>
              NonZero<i32>
              NonZero<i64>
              NonZero<i8>
              NonZero<isize>
              NonZero<u128>
              NonZero<u16>
            and 6 others
note: required by a bound in `bytemuck::cast_slice_mut`
   --> /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytemuck-1.16.3/src/lib.rs:367:6
    |
365 | pub fn cast_slice_mut<
    |        -------------- required by a bound in this function
366 |   A: NoUninit + AnyBitPattern,
367 |   B: NoUninit + AnyBitPattern,
    |      ^^^^^^^^ required by this bound in `cast_slice_mut`
help: consider specifying the generic arguments
    |
11  |     expect(bytemuck::cast_slice_mut::<u32, B>(slice));
    |                                    ++++++++++

error[E0283]: type annotations needed
  --> src/lib.rs:11:5
   |
11 |     expect(bytemuck::cast_slice_mut(slice));
   |     ^^^^^^ cannot infer type of the type parameter `B` declared on the function `expect`
   |
note: multiple `impl`s satisfying `[_]: Trait` found
  --> src/lib.rs:4:1
   |
4  | impl Trait for [u8] {}
   | ^^^^^^^^^^^^^^^^^^^
5  | impl Trait for [NonZero<u8>] {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required for `&mut [_]` to implement `Trait`
  --> src/lib.rs:3:25
   |
3  | impl<T: ?Sized + Trait> Trait for &mut T {}
   |                  -----  ^^^^^     ^^^^^^
   |                  |
   |                  unsatisfied trait bound introduced here
note: required by a bound in `expect`
  --> src/lib.rs:7:14
   |
7  | fn expect<B: Trait>(_: B) {}
   |              ^^^^^ required by this bound in `expect`
help: consider specifying the generic argument
   |
11 |     expect::<&mut [B]>(bytemuck::cast_slice_mut(slice));
   |           ++++++++++++

Desired output

error[E0283]: type annotations needed
   --> src/lib.rs:11:12
    |
11  |     expect(bytemuck::cast_slice_mut(slice));
    |            ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `B` declared on the function `cast_slice_mut`
    |
    = note: cannot satisfy `_: NoUninit`
    = help: the following types implement trait `NoUninit`:
              NonZero<i128>
              NonZero<i16>
              NonZero<i32>
              NonZero<i64>
              NonZero<i8>
              NonZero<isize>
              NonZero<u128>
              NonZero<u16>
            and 6 others
note: required by a bound in `bytemuck::cast_slice_mut`
   --> /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytemuck-1.16.3/src/lib.rs:367:6
    |
365 | pub fn cast_slice_mut<
    |        -------------- required by a bound in this function
366 |   A: NoUninit + AnyBitPattern,
367 |   B: NoUninit + AnyBitPattern,
    |      ^^^^^^^^ required by this bound in `cast_slice_mut`
help: consider specifying the generic arguments, where the type for type parameter `B` is specified
    |
11  |     expect(bytemuck::cast_slice_mut::<u32, B>(slice));
    |                                    ++++++++++

error[E0283]: type annotations needed
  --> src/lib.rs:11:5
   |
11 |     expect(bytemuck::cast_slice_mut(slice));
   |     ^^^^^^ cannot infer type of the type parameter `B` declared on the function `expect`
   |
note: multiple `impl`s satisfying `[_]: Trait` found
  --> src/lib.rs:4:1
   |
4  | impl Trait for [u8] {}
   | ^^^^^^^^^^^^^^^^^^^
5  | impl Trait for [NonZero<u8>] {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required for `&mut [_]` to implement `Trait`
  --> src/lib.rs:3:25
   |
3  | impl<T: ?Sized + Trait> Trait for &mut T {}
   |                  -----  ^^^^^     ^^^^^^
   |                  |
   |                  unsatisfied trait bound introduced here
note: required by a bound in `expect`
  --> src/lib.rs:7:14
   |
7  | fn expect<B: Trait>(_: B) {}
   |              ^^^^^ required by this bound in `expect`
help: consider specifying the generic argument, where the type for type parameter `B` is specified
   |
11 |     expect::<&mut [B]>(bytemuck::cast_slice_mut(slice));
   |           ++++++++++++

Rationale and extra context

In the face of ambiguity, E0283 suggestions print the name of generic parameters which were specified on the trait or function being called. Sometimes they tell you that you need to replace ("specify") those generic parameter names with concrete names, and sometimes they do not. The above code is an example of a case where they do not.

Here's the URLO issue that prompted this report.

The compiler-suggested fix,

bytemuck::cast_slice_mut::<u32, B>(&mut mapped_slice[range_start + 1..range_end]),

won't work because there is no "B" in scope at that point.

If you comment the the top half of test and uncomment the bottom half, you get the output under "Other cases" instead (which does tell you to replace the generic parameter name).

Other cases

error[E0283]: type annotations needed for `&mut [_]`
   --> src/lib.rs:14:9
    |
14  |     let cast = bytemuck::cast_slice_mut(slice);
    |         ^^^^   ------------------------------- type must be known at this point
    |
    = note: cannot satisfy `_: NoUninit`
    = help: the following types implement trait `NoUninit`:
              NonZero<i128>
              NonZero<i16>
              NonZero<i32>
              NonZero<i64>
              NonZero<i8>
              NonZero<isize>
              NonZero<u128>
              NonZero<u16>
            and 6 others
note: required by a bound in `bytemuck::cast_slice_mut`
   --> /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytemuck-1.16.3/src/lib.rs:367:6
    |
365 | pub fn cast_slice_mut<
    |        -------------- required by a bound in this function
366 |   A: NoUninit + AnyBitPattern,
367 |   B: NoUninit + AnyBitPattern,
    |      ^^^^^^^^ required by this bound in `cast_slice_mut`
help: consider giving `cast` an explicit type, where the type for type parameter `B` is specified
    |
14  |     let cast: &mut [B] = bytemuck::cast_slice_mut(slice);
    |             ++++++++++

error[E0283]: type annotations needed for `&mut [_]`
  --> src/lib.rs:14:9
   |
14 |     let cast = bytemuck::cast_slice_mut(slice);
   |         ^^^^
15 |     expect(cast);
   |     ------------ type must be known at this point
   |
note: multiple `impl`s satisfying `[_]: Trait` found
  --> src/lib.rs:4:1
   |
4  | impl Trait for [u8] {}
   | ^^^^^^^^^^^^^^^^^^^
5  | impl Trait for [NonZero<u8>] {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required for `&mut [_]` to implement `Trait`
  --> src/lib.rs:3:25
   |
3  | impl<T: ?Sized + Trait> Trait for &mut T {}
   |                  -----  ^^^^^     ^^^^^^
   |                  |
   |                  unsatisfied trait bound introduced here
note: required by a bound in `expect`
  --> src/lib.rs:7:14
   |
7  | fn expect<B: Trait>(_: B) {}
   |              ^^^^^ required by this bound in `expect`
help: consider giving `cast` an explicit type, where the type for slice `[_]` is specified
   |
14 |     let cast: &mut [B] = bytemuck::cast_slice_mut(slice);
   |             ++++++++++

Rust Version

Rust playground

Stable channel
Build using the Stable version: 1.80.0

Beta channel
Build using the Beta version: 1.81.0-beta.2
(2024-07-25 08328a323ecd80b443a8)

Nightly channel
Build using the Nightly version: 1.82.0-nightly
(2024-08-02 fd8d6fbe505ecf913f5e)

Anything else?

I don't know if "is specified" is the most immediately understandable suggestion, but that's really orthogonal to the point of this issue -- the messaging should consistently point out that the name used is a generic parameter name which you have to replace.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions