[PATCH 3/3] rust: pin-init: internal: init: use span of `<-` or `:` for the init/write call.

From: Gary Guo

Date: Mon Sep 28 2026 - 13:33:31 EST


Currently we use the full span of the field initializer as the span of the
generated init call. This produces overlapping spans for type mismatch
errors, which is hard to read.

Use the span of `<-` or `:` for the method name, which wll cause type
mismatch errors or trait bound not implemented error to be appear from the
`<-` or `:` token, which declutter the output a bit and make it easier to
read.

Before the 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

After the 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

Suggested-by: Benno Lossin <lossin@xxxxxxxxxx>
Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
---
rust/pin-init/internal/src/init.rs | 38 +++++++++++++++++++++++++++-----------
1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index f6f3e2f8cda6..6605e04d49df 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -101,7 +101,7 @@ enum InitializerKind {
},
Init {
member: Member,
- _left_arrow_token: Token![<-],
+ left_arrow_token: Token![<-],
value: Expr,
},
Code {
@@ -415,24 +415,40 @@ fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -

// `mixed_site` ensures that the guard is not accessible to the user-controlled code.
let guard = format_ident!("__{ident}_guard", span = Span::mixed_site());
- let full_span = kind.span();
+ let full_span = kind.span().resolved_at(Span::mixed_site());

let init = match kind {
InitializerKind::Value { value, .. } => {
- let value = value
+ let (colon_span, value) = value
.as_ref()
- .map(|(_, value)| quote!(#value))
- .unwrap_or_else(|| quote!(#member));
+ .map(|(colon_token, value)| (colon_token.span(), quote!(#value)))
+ .unwrap_or_else(|| (member.span(), quote!(#member)));
+
+ // Use `:` as the span of the method name, so the type requirement appears to come
+ // from `:`.
+ let write =
+ format_ident!("write", span = colon_span.resolved_at(Span::mixed_site()));

quote_spanned! { full_span =>
#(#attrs)*
- let mut #guard = #slot.write(#value);
+ let mut #guard = #slot.#write(#value);
}
}
- InitializerKind::Init { value, .. } => {
+ InitializerKind::Init {
+ value,
+ left_arrow_token,
+ ..
+ } => {
+ // Use `<-` as the span of the method name, so the trait bound appears to come from
+ // `<-`.
+ let init = format_ident!(
+ "init",
+ span = left_arrow_token.span().resolved_at(Span::mixed_site())
+ );
+
quote_spanned! { full_span =>
#(#attrs)*
- let mut #guard = #slot.init(#value)?;
+ let mut #guard = #slot.#init(#value)?;
}
}
InitializerKind::Code { .. } => unreachable!(),
@@ -690,7 +706,7 @@ fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
if lh.peek(Token![<-]) {
Ok(Self::Init {
member,
- _left_arrow_token: input.parse()?,
+ left_arrow_token: input.parse()?,
value: input.parse()?,
})
} else if lh.peek(Token![:]) {
@@ -819,11 +835,11 @@ fn to_tokens(&self, tokens: &mut TokenStream) {
}
Self::Init {
member,
- _left_arrow_token,
+ left_arrow_token,
value,
} => {
member.to_tokens(tokens);
- _left_arrow_token.to_tokens(tokens);
+ left_arrow_token.to_tokens(tokens);
value.to_tokens(tokens);
}
Self::Code {

--
2.54.0