+59
-5
futures-derive/src/lib.rs
+59
-5
futures-derive/src/lib.rs
···
1
use proc_macro::TokenStream;
2
-
use quote::quote;
3
use syn::{
4
-
Expr, ExprAwait, FnArg, ItemFn, Pat, ReturnType, Signature,
5
-
parse_macro_input, visit_mut::VisitMut,
6
};
7
8
#[proc_macro_attribute]
···
75
})
76
.collect();
77
78
-
// let has_refs = inputs
79
80
quote! {
81
-
#(#attrs)* #vis #constness #unsafety fn #ident #generics (#inputs) -> impl futures_core::ScopedFuture<'_, Output = #output> + '_ {
82
async #constness #unsafety fn __inner (#inputs) -> #output #block
83
84
let future = __inner(#(#inner_args),*);
85
86
unsafe { futures_compat::UnscopedFutureWrapper::from_future(future) }
87
}
88
}
89
}
90
···
1
use proc_macro::TokenStream;
2
+
use quote::{ToTokens, quote};
3
use syn::{
4
+
Expr, ExprAwait, FnArg, GenericArgument, ItemFn, Pat, ReturnType,
5
+
Signature, parse_macro_input, visit_mut::VisitMut,
6
};
7
8
#[proc_macro_attribute]
···
75
})
76
.collect();
77
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
+
};
88
89
quote! {
90
+
#(#attrs)* #vis #constness #unsafety fn #ident #generics (#inputs) -> impl #outer_output {
91
async #constness #unsafety fn __inner (#inputs) -> #output #block
92
93
let future = __inner(#(#inner_args),*);
94
95
unsafe { futures_compat::UnscopedFutureWrapper::from_future(future) }
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,
142
}
143
}
144