Implicit elided lifetime not allowed here expected lifetime parameter

Hi, I have been trying to experiment on proc macros after getting quite comfortable with core rust. but for some unknown reason I am facing some error with lifetime annotation in struct.

use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{Data, Ident};

#[proc_macro_derive(IntoHashMap)]
pub fn into_hash_map(item: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::DeriveInput);

    let struct_identifier = &input.ident;
    let struct_identifier_to_string = struct_identifier.to_string().to_uppercase();
    let struct_union_identifier = Ident::new(&format!("{}_UNION", struct_identifier_to_string), Span::call_site());

    match &input.data {
        Data::Struct(syn::DataStruct { fields, .. }) => {
            let field_identifiers = fields.iter().map(|item| item.ident.as_ref().unwrap()).collect::<Vec<_>>();

            let field_types = fields.iter().map(|item| item.ty.clone()).collect::<Vec<_>>();

            quote! {
                union #struct_union_identifier {
                    #(
                        #field_identifiers: #field_types,
                    )*
                }
                
                impl From<#struct_identifier> for std::collections::HashMap<String,  #struct_union_identifier> {
                    fn from(value: #struct_identifier) -> Self {
                        let mut hash_map = std::collections::HashMap::<String, #struct_union_identifier>::new();

                        #(
                            hash_map.insert(
                                stringify!(#field_identifiers).to_string(), 
                                #struct_union_identifier { #field_identifiers: value.#field_identifiers }
                            );
                        )*

                        hash_map
                    }
                }
            }
        }
        _ => unimplemented!()
    }.into()
}

above is the derive macro to convert a struct into a hashmap. And when I try to derive the above macro,

#[derive(Clone, PartialEq, Debug, IntoHashMap)]
struct Person<'a> { **// implicit elided lifetime not allowed here, expected lifetime parameter**
    name: &'a str, **// use of undeclared lifetime name `'a` undeclared lifetime**
    age: u8,
}

the lifetime annotation 'a is allowed. Is this some sort of hidden quirk?

Well, you are only ever emitting the name of the input type, you are never mentioning any of the generic arguments. Why should they appear, then?

even after adding lifetimes to the union, the issue remains the same,

use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{Data, Ident};

#[proc_macro_derive(IntoHashMap)]
pub fn into_hash_map(item: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::DeriveInput);

    let struct_identifier = &input.ident;
    let struct_identifier_to_string = struct_identifier.to_string().to_uppercase();
    let struct_union_identifier = Ident::new(&format!("{}_UNION", struct_identifier_to_string), Span::call_site());

    // lifetimes are iterated here....
    let lifetimes = input.generics.lifetimes().collect::<Vec<_>>();

    match &input.data {
        Data::Struct(syn::DataStruct { fields, .. }) => {
            let field_identifiers = fields.iter().map(|item| item.ident.as_ref().unwrap()).collect::<Vec<_>>();

            let field_types = fields.iter().map(|item| item.ty.clone()).collect::<Vec<_>>();

            quote! {
                union #struct_union_identifier<#(#lifetimes,)*> {
                    #(
                        #field_identifiers: #field_types,
                    )*
                }
                
                impl From<#struct_identifier> for std::collections::HashMap<String,  #struct_union_identifier> {
                    fn from(value: #struct_identifier) -> Self {
                        let mut hash_map = std::collections::HashMap::<String, #struct_union_identifier>::new();

                        #(
                            hash_map.insert(
                                stringify!(#field_identifiers).to_string(), 
                                #struct_union_identifier { #field_identifiers: value.#field_identifiers }
                            );
                        )*

                        hash_map
                    }
                }
            }
        }
        _ => unimplemented!()
    }.into()
}

here is the error message:

error[E0726]: implicit elided lifetime not allowed here
 --> src/main.rs:8:8
  |
8 | struct Person<'a> {
  |        ^^^^^^ expected lifetime parameter
  |
help: indicate the anonymous lifetime
  |
8 | struct Person<'_><'a> {
  |              ++++

error[E0726]: implicit elided lifetime not allowed here
 --> src/main.rs:7:35
  |
7 | ...Eq, Debug, IntoHashMap)]
  |               ^^^^^^^^^^^ expected lifetime parameter
  |
  = note: this error originates in the derive macro `IntoHashMap` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0726`.
error: could not compile `rust_project_01` (bin "rust_project_01") due to 2 previous errors

Obviously, the generic params of the input shouldn't be added to a completely unrelated type. They should be added back to the original input type.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.