Rustc note providing malformed code when run with proc_macro

⚓ Rust    📅 2025-12-13    👤 surdeus    👁️ 1      

surdeus

When I try to run this code, it fails:

#[derive(MyFrom)]
struct MyTupleGeneric<T> {
    name: T
}

where this is the proc_macro I used:

extern crate proc_macro;
use proc_macro::TokenStream;

use syn::{parse_macro_input, Data, DeriveInput, Fields};
use quote::quote;
use syn::spanned::Spanned;

#[proc_macro_derive(MyFrom)]
pub fn my_derive(input: TokenStream) -> TokenStream {
    let derived_input = parse_macro_input!(input as DeriveInput);
    let ident = &derived_input.ident;
    if let Data::Struct(data) = derived_input.data {
        match data.fields {
            Fields::Named(fields) => {
                if fields.named.len() != 1 {
                    return syn::Error::new(fields.span(), "#[derive(MyFrom)] cannot be implemented on anything other than a struct with one field").to_compile_error().into();
                }
                let field = fields.named.first().unwrap();
                let name = field.ident.as_ref().unwrap();
                let field_type = field.ty.clone();
                if derived_input.generics.params.is_empty() {
                    quote! {
                        impl From<#field_type> for #ident {
                            fn from(value: #field_type) -> Self {
                                Self {
                                    #name: value
                                }
                            }
                        }
                    }.into()
                } else {
                    let generics = derived_input.generics.params;
                    if let Some(where_clause) = derived_input.generics.where_clause {
                        quote! {
                            impl<#generics> From<#field_type> for #ident #where_clause {
                                fn from(value: #field_type) -> Self {
                                    Self {
                                        #name: value
                                    }
                                }
                            }
                        }.into()
                    } else {
                        quote! {
                            impl<#generics> From<#field_type> for #ident {
                                fn from(value: #field_type) -> Self {
                                    Self {
                                        #name: value
                                    }
                                }
                            }
                        }.into()
                    }
                }
            },
            Fields::Unnamed(fields) => {
                if fields.unnamed.len() != 1 {
                    return syn::Error::new(fields.span(), "#[derive(MyFrom)] cannot be implemented on anything other than a struct with one field").to_compile_error().into();
                }
                let field = fields.unnamed.first().unwrap();
                let field_type = field.ty.clone();
                if derived_input.generics.params.is_empty() {
                    quote! {
                        impl From<#field_type> for #ident {
                            fn from(value: #field_type) -> Self {
                                Self(value)
                            }
                        }
                    }.into()
                } else {
                    let generics = derived_input.generics.params;
                    if let Some(where_clause) = derived_input.generics.where_clause {
                        quote! {
                            impl<#generics> From<#field_type> for #ident #where_clause {
                                fn from(value: #field_type) -> Self {
                                    Self(value)
                                }
                            }
                        }.into()
                    } else {
                        quote! {
                            impl<#generics> From<#field_type> for #ident {
                                fn from(value: #field_type) -> Self {
                                    Self(value)
                                }
                            }
                        }.into()
                    }
                }
            },
            Fields::Unit => {
                syn::Error::new(ident.span(), "#[derive(MyFrom)] cannot be implemented on anything other than a struct with one field").to_compile_error().into()
            }
        }
    } else {
        syn::Error::new(ident.span(), "#[derive(MyFrom)] cannot be implemented on anything other than a struct with one field").to_compile_error().into()
    }
}

returns this very malformed error:

error[E0107]: missing generics for struct `MyTupleGeneric`                                                                                                                      
  --> derive_from\tests\from_works.rs:12:8
   |
12 | struct MyTupleGeneric<T> {
   |        ^^^^^^^^^^^^^^ expected 1 generic argument
   |
note: struct defined here, with 1 generic parameter: `T`
  --> derive_from\tests\from_works.rs:12:8
   |
12 | struct MyTupleGeneric<T> {
   |        ^^^^^^^^^^^^^^ -
help: add missing generic argument
   |
12 | struct MyTupleGeneric<T><T> {

Shouldn't the missing generics be on the impl From block?
After I fixed it by adding the generic param to the ident, it worked well, but I am wondering why it showed this "wrong" note.

1 post - 1 participant

Read full topic

🏷️ Rust_feed