From b2cb983f9d59ddc0ede2a4976443fda6297778af Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 28 Sep 2026 18:32:21 +0100 Subject: [PATCH] rust: pin-init: internal: init: use span of `<-` or `:` for the init/write call. 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` 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` is not implemented for `impl pin_init::PinInit` | 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` 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` is not implemented for `impl pin_init::PinInit` | | | 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 Link: https://patch.msgid.link/20260928-dev-pin-init-sync-v1-3-e591c8e9cf0e@garyguo.net Signed-off-by: Gary Guo --- 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, 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 { 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 {