Skip to content

Improve diagnostics of missing #[pin_data] and #[pin] - #178

Merged
nbdd0121 merged 6 commits into
mainfrom
dev/pin-data-diag
Sep 25, 2026
Merged

nbdd0121 merged 6 commits into
mainfrom
dev/pin-data-diag

Conversation

@nbdd0121

@nbdd0121 nbdd0121 commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Improve the diagnostics of missing #[pin_data] and #[pin], by adding
diagnostics attributes. For #[pin_data], we have to change the expansion
to retrieve PinData in a two-step process, so we change the error message
from "method exists but trait bound not satisfied" to "trait not
implemented".

This is the new error message for missing #[pin_data]:

error[E0277]: `Foo` cannot be used with `pin_init!` macro
 --> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
  |
9 |         pin_init!(Self { a: 42 })
  |                   ^^^^ unsatisfied trait bound
  |
help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`

where it was previously

error[E0599]: no associated function or constant named `__pin_data` found for struct `Foo` in the current scope
 --> tests/ui/compile-fail/init/missing_pin_data.rs:9:9
  |
3 | struct Foo {
  | ---------- associated function or constant `__pin_data` not found for this struct
...
9 |         pin_init!(Self { a: 42 })
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^ associated function or constant not found in `Foo`
  |
  = help: items from traits can only be used if the trait is implemented and in scope
  = note: the following trait defines an item `__pin_data`, perhaps you need to implement it:
          candidate #1: `pin_init::__internal::HasPinData`

and this is the new error message for missing #[pin]:

error[E0277]: `impl PinInit<usize>` cannot be used to movably initialize `usize` with error `_`
  --> tests/ui/compile-fail/pin_data/missing_pin.rs:12:18
   |
12 |             a <- a,
   |             -----^
   |             |    |
   |             |    the trait `Init<usize, _>` is not implemented for `impl PinInit<usize>`
   |             required by a bound introduced by this call
   |
   = note: if your type implements `PinInit` but not `Init`, you might be forgetting a `#[pin]` annotation on fields

where it was previously

error[E0277]: the trait bound `impl pin_init::PinInit<Bar>: Init<Bar, _>` is not satisfied
  --> tests/ui/compile-fail/init/invalid_init.rs:19:16
   |
19 |         bar <- Bar::new(),
   |         -------^^^^^^^^^^
   |         |      |
   |         |      the trait `Init<Bar, _>` is not implemented for `impl pin_init::PinInit<Bar>`
   |         required by a bound introduced by this call

Remove the unsafe markers of `__init_data` and `__pin_data`. These methods
are for inference help and does not need to be unsafe.

The `HasInitData` cannot be implemented outside pin-init, so the `unsafe
trait` marker is not necessary.

Signed-off-by: Gary Guo <gary@garyguo.net>
There is only a single implementation, the associated type is not
necessary. Remove it, and rename `AllData` to `InitData` to be a more
meaningful name.

The single implementation also means that "unsafe" is redundant, so remove
it as well.

Signed-off-by: Gary Guo <gary@garyguo.net>
Currently, type inference of the initialized type is done by use the
function calling syntax `PATH::__pin_data` or `PATH::__init_data` to obtain
the required init data type, without needing the user to explicitly mention
all generics. Switch to always use `HasInitData::__init_data` to provide
that inference, which will not produce method-not-found errors as it is
always available.

Change `__pin_data` to take `InitData<Self>` as the receiver, so for types
that require `HasPinData`, `HasPinData::__pin_data(data)` can be used to
obtain the needed type without having to mention the user-provided path
again. The expanded code also uses the span of the type, so diagnostics
will hint to user that the type is causing the issue.

With this change, the error message when `HasPinData` is not implemented
changes from

    error[E0599]: no associated function or constant named `__pin_data` found for struct `Foo` in the current scope
     --> tests/ui/compile-fail/init/missing_pin_data.rs:9:9
      |
    3 | struct Foo {
      | ---------- associated function or constant `__pin_data` not found for this struct
    ...
    9 |         pin_init!(Self { a: 42 })
      |         ^^^^^^^^^^^^^^^^^^^^^^^^^ associated function or constant not found in `Foo`
      |
      = help: items from traits can only be used if the trait is implemented and in scope
      = note: the following trait defines an item `__pin_data`, perhaps you need to implement it:
              candidate #1: `pin_init::__internal::HasPinData`

to

    error[E0277]: the trait bound `Foo: pin_init::__internal::HasPinData` is not satisfied
     --> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
      |
    9 |         pin_init!(Self { a: 42 })
      |                   ^^^^ unsatisfied trait bound
      |
    help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`
     --> tests/ui/compile-fail/init/missing_pin_data.rs:3:1
      |
    3 | struct Foo {
      | ^^^^^^^^^^

Signed-off-by: Gary Guo <gary@garyguo.net>
Produce a more helpful error message when `#[pin_data]` is omitted. The
error message changes from

    error[E0277]: the trait bound `Foo: pin_init::__internal::HasPinData` is not satisfied
     --> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
      |
    9 |         pin_init!(Self { a: 42 })
      |                   ^^^^ unsatisfied trait bound
      |
    help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`
     --> tests/ui/compile-fail/init/missing_pin_data.rs:3:1
      |
    3 | struct Foo {
      | ^^^^^^^^^^

to

    error[E0277]: `Foo` cannot be used with `pin_init!` macro
     --> tests/ui/compile-fail/init/missing_pin_data.rs:9:19
      |
    9 |         pin_init!(Self { a: 42 })
      |                   ^^^^ unsatisfied trait bound
      |
    help: the trait `pin_init::__internal::HasPinData` is not implemented for `Foo`
     --> tests/ui/compile-fail/init/missing_pin_data.rs:3:1
      |
    3 | struct Foo {
      | ^^^^^^^^^^
      = note: did you forget to add `#[pin_data]` attribute to the struct?

Signed-off-by: Gary Guo <gary@garyguo.net>
Give a slightly more useful error message when these traits are not
implemented.

Before this change:

    error[E0277]: the trait bound `impl pin_init::PinInit<Bar>: Init<Bar, _>` is not satisfied
      --> tests/ui/compile-fail/init/invalid_init.rs:19:16
       |
    19 |         bar <- Bar::new(),
       |         -------^^^^^^^^^^
       |         |      |
       |         |      the trait `Init<Bar, _>` is not implemented for `impl pin_init::PinInit<Bar>`
       |         required by a bound introduced by this call

After this change:

    error[E0277]: `impl pin_init::PinInit<Bar>` cannot be used to movably initialize `Bar` with error `_`
      --> tests/ui/compile-fail/init/invalid_init.rs:19:16
       |
    19 |         bar <- Bar::new(),
       |         -------^^^^^^^^^^
       |         |      |
       |         |      the trait `Init<Bar, _>` is not implemented for `impl pin_init::PinInit<Bar>`
       |         required by a bound introduced by this call
       |
       = note: if your type implements `PinInit` but not `Init`, you might be forgetting a `#[pin]` annotation on fields

Ideally, we would generate differnet message when `PinInit` is implemented
but not `Init`; that is not feasible with today's
`diagnostics::on_unimplemented` attribute. However, the added note is worth
it because in `init!()` is more rarely used compared to `pin_init!()`; in
most cases `Init` being unimplemented is the result of missing `#[pin]`.

Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
@nbdd0121
nbdd0121 merged commit 12a218c into main Sep 25, 2026
55 checks passed
@nbdd0121
nbdd0121 deleted the dev/pin-data-diag branch September 25, 2026 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant