fix async_scoped 'static return type

Changed files
+59 -5
futures-derive
src
+59 -5
futures-derive/src/lib.rs
··· 1 1 use proc_macro::TokenStream; 2 - use quote::quote; 2 + use quote::{ToTokens, quote}; 3 3 use syn::{ 4 - Expr, ExprAwait, FnArg, ItemFn, Pat, ReturnType, Signature, 5 - parse_macro_input, visit_mut::VisitMut, 4 + Expr, ExprAwait, FnArg, GenericArgument, ItemFn, Pat, ReturnType, 5 + Signature, parse_macro_input, visit_mut::VisitMut, 6 6 }; 7 7 8 8 #[proc_macro_attribute] ··· 75 75 }) 76 76 .collect(); 77 77 78 - // let has_refs = inputs 78 + let has_lifetime_dependency = inputs.iter().any(|param| match param { 79 + FnArg::Receiver(receiver) => receiver.reference.is_some(), 80 + FnArg::Typed(pat) => has_lifetime_dependency(&pat.ty), 81 + }); 82 + 83 + let outer_output = if has_lifetime_dependency { 84 + quote! { futures_core::ScopedFuture<'_, Output = #output> + '_ } 85 + } else { 86 + quote! { futures_core::ScopedFuture<'static, Output = #output> } 87 + }; 79 88 80 89 quote! { 81 - #(#attrs)* #vis #constness #unsafety fn #ident #generics (#inputs) -> impl futures_core::ScopedFuture<'_, Output = #output> + '_ { 90 + #(#attrs)* #vis #constness #unsafety fn #ident #generics (#inputs) -> impl #outer_output { 82 91 async #constness #unsafety fn __inner (#inputs) -> #output #block 83 92 84 93 let future = __inner(#(#inner_args),*); 85 94 86 95 unsafe { futures_compat::UnscopedFutureWrapper::from_future(future) } 87 96 } 97 + } 98 + } 99 + 100 + /// Determines if typed pattern contains a reference or dependency on a 101 + /// lifetime (used for deciding between '_ and 'static ScopedFuture). 102 + fn has_lifetime_dependency(ty: &syn::Type) -> bool { 103 + match ty { 104 + syn::Type::Reference(_) => true, 105 + syn::Type::Path(type_path) => { 106 + type_path.path.segments.iter().any(|segment| { 107 + if let syn::PathArguments::AngleBracketed(args) = 108 + &segment.arguments 109 + { 110 + args.args.iter().any(|arg| match arg { 111 + GenericArgument::Type(ty) => { 112 + has_lifetime_dependency(ty) 113 + } 114 + syn::GenericArgument::Lifetime(_) => true, 115 + _ => false, 116 + }) 117 + } else { 118 + false 119 + } 120 + }) 121 + } 122 + syn::Type::Tuple(tuple) => { 123 + tuple.elems.iter().any(has_lifetime_dependency) 124 + } 125 + syn::Type::Slice(slice) => has_lifetime_dependency(&slice.elem), 126 + syn::Type::Array(array) => has_lifetime_dependency(&array.elem), 127 + syn::Type::Ptr(ptr) => has_lifetime_dependency(&ptr.elem), 128 + syn::Type::Group(group) => has_lifetime_dependency(&group.elem), 129 + syn::Type::Paren(paren) => has_lifetime_dependency(&paren.elem), 130 + syn::Type::BareFn(bare_fn) => { 131 + bare_fn 132 + .inputs 133 + .iter() 134 + .any(|input| has_lifetime_dependency(&input.ty)) 135 + || match &bare_fn.output { 136 + ReturnType::Default => false, 137 + ReturnType::Type(_, ty) => has_lifetime_dependency(ty), 138 + } 139 + } 140 + 141 + _ => false, 88 142 } 89 143 } 90 144