Repository: tokio-rs/axum
File: axum-macros/src/debug_handler.rs (Rust)

Code before:
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned};
use syn::{parse::Parse, parse_quote, spanned::Spanned, FnArg, ItemFn, Token, Type};

pub(crate) fn expand(attr: Attrs, item_fn: ItemFn) -> TokenStream {
    let Attrs { body_ty, state_ty } = attr;

    let body_ty = body_ty
        .map(second)
        .unwrap_or_else(|| parse_quote!(axum::body::Body));

    let mut state_ty = state_ty.map(second);

    let check_extractor_count = check_extractor_count(&item_fn);
    let check_path_extractor = check_path_extractor(&item_fn);
    let check_output_impls_into_response = check_output_impls_into_response(&item_fn);

    // If the function is generic, we can't reliably check its inputs or whether the future it
    // returns is `Send`. Skip those checks to avoid unhelpful additional compiler errors.
    let check_inputs_and_future_send = if item_fn.sig.generics.params.is_empty() {
        if state_ty.is_none() {
            let state_types_from_args = state_types_from_args(&item_fn);
            if state_types_from_args.len() == 1 {
                state_ty = state_types_from_args.into_iter().next();
            } // FIXME: if len > 1, error?
        }

        let state_ty = state_ty.unwrap_or_else(|| syn::parse_quote!(()));

        let check_inputs_impls_from_request =
            check_inputs_impls_from_request(&item_fn, &body_ty, state_ty);
        let check_future_send = check_future_send(&item_fn);

        quote! {
            #check_inputs_impls_from_request
            #check_future_send
        }
    } else {
        syn::Error::new_spanned(
            &item_fn.sig.generics,
            "`#[axum_macros::debug_handler]` doesn't support generic functions",
        )
        .into_compile_error()
    };

    quote! {
        #item_fn
        #check_extractor_count
        #check_path_extractor
        #check_output_impls_into_response

Review comment (suggestion):
I think this should be an error yes 🤔 I think it would probably produce a type error somewhere else anyway

Code after:
};
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote, quote_spanned};
use syn::{parse::Parse, parse_quote, spanned::Spanned, FnArg, ItemFn, Token, Type};

pub(crate) fn expand(attr: Attrs, item_fn: ItemFn) -> TokenStream {
    let Attrs { body_ty, state_ty } = attr;

    let body_ty = body_ty
        .map(second)
        .unwrap_or_else(|| parse_quote!(axum::body::Body));

    let mut state_ty = state_ty.map(second);

    let check_extractor_count = check_extractor_count(&item_fn);
    let check_path_extractor = check_path_extractor(&item_fn);
    let check_output_impls_into_response = check_output_impls_into_response(&item_fn);

    // If the function is generic, we can't reliably check its inputs or whether the future it
    // returns is `Send`. Skip those checks to avoid unhelpful additional compiler errors.
    let check_inputs_and_future_send = if item_fn.sig.generics.params.is_empty() {
        let mut err = None;

        if state_ty.is_none() {
            let state_types_from_args = state_types_from_args(&item_fn);

            #[allow(clippy::comparison_chain)]
            if state_types_from_args.len() == 1 {
                state_ty = state_types_from_args.into_iter().next();
            } else if state_types_from_args.len() > 1 {
                err = Some(
                    syn::Error::new(
                        Span::call_site(),
                        "can't infer state type, please add set it explicitly, as in \
                         `#[debug_handler(state = MyStateType)]`",
                    )
                    .into_compile_error(),
                );
            }
        }

        err.unwrap_or_else(|| {
            let state_ty = state_ty.unwrap_or_else(|| syn::parse_quote!(()));

            let check_inputs_impls_from_request =
                check_inputs_impls_from_request(&item_fn, &body_ty, state_ty);
            let check_future_send = check_future_send(&item_fn);

            quote! {
                #check_inputs_impls_from_request
                #check_future_send