rust: pin-init: internal: init: provide span for slot projection

When initializing a field, pin-init first projects the full slot to a slot
of the field, then initialize it by invoking a method. Currently the span
location is not explicitly set, so the error message points to the full
macro invocation.

Improve it by provide a span, so Rust will point to the specific fields
causing the error when type check fails.

Old error message:

    error[E0308]: mismatched types
     --> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28
      |
    8 |     let _ = init!(Foo { a: () });
      |             ---------------^^---
      |             |              |
      |             |              expected `usize`, found `()`
      |             arguments to this method are incorrect

New error message:

    error[E0308]: mismatched types
     --> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28
      |
    8 |     let _ = init!(Foo { a: () });
      |                         ---^^
      |                         |  |
      |                         |  expected `usize`, found `()`
      |                         arguments to this method are incorrect

Link: https://patch.msgid.link/20260916-dev-hygiene-v1-3-dfb6ae2588ba@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
This commit is contained in:
Gary Guo 2026-09-16 13:11:34 +01:00
parent 7f849c19e2
commit fb3d5c6b4c

View File

@ -404,9 +404,10 @@ fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -
}
};
let ident = member.as_ident();
let span = Span::mixed_site().located_at(ident.span());
let slot = if pinned {
quote_spanned! { Span::mixed_site() =>
quote_spanned! { span =>
// SAFETY:
// - `slot` is valid and properly aligned.
// - `make_field_check` checks that `&raw mut (*slot).#member` is properly aligned.
@ -415,7 +416,7 @@ fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -
(unsafe { data.#ident(slot) })
}
} else {
quote_spanned! { Span::mixed_site() =>
quote_spanned! { span =>
// For `init!()` macro, everything is unpinned.
// SAFETY:
// - `&raw mut (*slot).#member` is valid.
@ -432,6 +433,7 @@ 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 init = match kind {
InitializerKind::Value { value, .. } => {
@ -440,14 +442,13 @@ fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -
.map(|(_, value)| quote!(#value))
.unwrap_or_else(|| quote!(#member));
quote! {
quote_spanned! { full_span =>
#(#attrs)*
let mut #guard = #slot.write(#value);
}
}
InitializerKind::Init { value, .. } => {
quote! {
quote_spanned! { full_span =>
#(#attrs)*
let mut #guard = #slot.init(#value)?;
}
@ -458,7 +459,7 @@ fn init_fields(fields: &Punctuated<InitializerField, Token![,]>, pinned: bool) -
// A tuple field has no name that could be bound here (the `_0` identifiers are considered
// implementation detail and not user-facing).
let binding = match member {
Member::Named(ident) => quote! {
Member::Named(ident) => quote_spanned! { span =>
#(#cfgs)*
// Allow `non_snake_case` since the same warning is going to be reported for the
// struct field.