Fix some holdouts from using argument holders for lifetime extensions.
This commit is contained in:
parent
3583b9ac67
commit
d75d4bdf81
|
@ -103,12 +103,18 @@ impl FnType {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn self_arg(&self, cls: Option<&syn::Type>, error_mode: ExtractErrorMode) -> TokenStream {
|
||||
pub fn self_arg(
|
||||
&self,
|
||||
cls: Option<&syn::Type>,
|
||||
error_mode: ExtractErrorMode,
|
||||
holders: &mut Vec<TokenStream>,
|
||||
) -> TokenStream {
|
||||
match self {
|
||||
FnType::Getter(st) | FnType::Setter(st) | FnType::Fn(st) => {
|
||||
let mut receiver = st.receiver(
|
||||
cls.expect("no class given for Fn with a \"self\" receiver"),
|
||||
error_mode,
|
||||
holders,
|
||||
);
|
||||
syn::Token![,](Span::call_site()).to_tokens(&mut receiver);
|
||||
receiver
|
||||
|
@ -161,7 +167,12 @@ impl ExtractErrorMode {
|
|||
}
|
||||
|
||||
impl SelfType {
|
||||
pub fn receiver(&self, cls: &syn::Type, error_mode: ExtractErrorMode) -> TokenStream {
|
||||
pub fn receiver(
|
||||
&self,
|
||||
cls: &syn::Type,
|
||||
error_mode: ExtractErrorMode,
|
||||
holders: &mut Vec<TokenStream>,
|
||||
) -> TokenStream {
|
||||
// Due to use of quote_spanned in this function, need to bind these idents to the
|
||||
// main macro callsite.
|
||||
let py = syn::Ident::new("py", Span::call_site());
|
||||
|
@ -173,10 +184,15 @@ impl SelfType {
|
|||
} else {
|
||||
syn::Ident::new("extract_pyclass_ref", *span)
|
||||
};
|
||||
let holder = syn::Ident::new(&format!("holder_{}", holders.len()), *span);
|
||||
holders.push(quote_spanned! { *span =>
|
||||
#[allow(clippy::let_unit_value)]
|
||||
let mut #holder = _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT;
|
||||
});
|
||||
error_mode.handle_error(quote_spanned! { *span =>
|
||||
_pyo3::impl_::extract_argument::#method::<#cls>(
|
||||
#py.from_borrowed_ptr::<_pyo3::PyAny>(#slf),
|
||||
&mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
|
||||
&mut #holder,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -457,9 +473,6 @@ impl<'a> FnSpec<'a> {
|
|||
ident: &proc_macro2::Ident,
|
||||
cls: Option<&syn::Type>,
|
||||
) -> Result<TokenStream> {
|
||||
let self_arg = self.tp.self_arg(cls, ExtractErrorMode::Raise);
|
||||
let func_name = &self.name;
|
||||
|
||||
let mut cancel_handle_iter = self
|
||||
.signature
|
||||
.arguments
|
||||
|
@ -473,7 +486,9 @@ impl<'a> FnSpec<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
let rust_call = |args: Vec<TokenStream>| {
|
||||
let rust_call = |args: Vec<TokenStream>, holders: &mut Vec<TokenStream>| {
|
||||
let self_arg = self.tp.self_arg(cls, ExtractErrorMode::Raise, holders);
|
||||
|
||||
let call = if self.asyncness.is_some() {
|
||||
let throw_callback = if cancel_handle.is_some() {
|
||||
quote! { Some(__throw_callback) }
|
||||
|
@ -486,14 +501,22 @@ impl<'a> FnSpec<'a> {
|
|||
None => quote!(None),
|
||||
};
|
||||
let future = match self.tp {
|
||||
FnType::Fn(SelfType::Receiver { mutable: false, .. }) => quote! {{
|
||||
let __guard = _pyo3::impl_::coroutine::RefGuard::<#cls>::new(py.from_borrowed_ptr::<_pyo3::types::PyAny>(_slf))?;
|
||||
async move { function(&__guard, #(#args),*).await }
|
||||
}},
|
||||
FnType::Fn(SelfType::Receiver { mutable: true, .. }) => quote! {{
|
||||
let mut __guard = _pyo3::impl_::coroutine::RefMutGuard::<#cls>::new(py.from_borrowed_ptr::<_pyo3::types::PyAny>(_slf))?;
|
||||
async move { function(&mut __guard, #(#args),*).await }
|
||||
}},
|
||||
FnType::Fn(SelfType::Receiver { mutable: false, .. }) => {
|
||||
holders.pop().unwrap(); // does not actually use holder created by `self_arg`
|
||||
|
||||
quote! {{
|
||||
let __guard = _pyo3::impl_::coroutine::RefGuard::<#cls>::new(py.from_borrowed_ptr::<_pyo3::types::PyAny>(_slf))?;
|
||||
async move { function(&__guard, #(#args),*).await }
|
||||
}}
|
||||
}
|
||||
FnType::Fn(SelfType::Receiver { mutable: true, .. }) => {
|
||||
holders.pop().unwrap(); // does not actually use holder created by `self_arg`
|
||||
|
||||
quote! {{
|
||||
let mut __guard = _pyo3::impl_::coroutine::RefMutGuard::<#cls>::new(py.from_borrowed_ptr::<_pyo3::types::PyAny>(_slf))?;
|
||||
async move { function(&mut __guard, #(#args),*).await }
|
||||
}}
|
||||
}
|
||||
_ => quote! { function(#self_arg #(#args),*) },
|
||||
};
|
||||
let mut call = quote! {{
|
||||
|
@ -519,6 +542,7 @@ impl<'a> FnSpec<'a> {
|
|||
quotes::map_result_into_ptr(quotes::ok_wrap(call))
|
||||
};
|
||||
|
||||
let func_name = &self.name;
|
||||
let rust_name = if let Some(cls) = cls {
|
||||
quote!(#cls::#func_name)
|
||||
} else {
|
||||
|
@ -527,6 +551,7 @@ impl<'a> FnSpec<'a> {
|
|||
|
||||
Ok(match self.convention {
|
||||
CallingConvention::Noargs => {
|
||||
let mut holders = Vec::new();
|
||||
let args = self
|
||||
.signature
|
||||
.arguments
|
||||
|
@ -541,7 +566,7 @@ impl<'a> FnSpec<'a> {
|
|||
}
|
||||
})
|
||||
.collect();
|
||||
let call = rust_call(args);
|
||||
let call = rust_call(args, &mut holders);
|
||||
|
||||
quote! {
|
||||
unsafe fn #ident<'py>(
|
||||
|
@ -549,13 +574,15 @@ impl<'a> FnSpec<'a> {
|
|||
_slf: *mut _pyo3::ffi::PyObject,
|
||||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||
#( #holders )*
|
||||
#call
|
||||
}
|
||||
}
|
||||
}
|
||||
CallingConvention::Fastcall => {
|
||||
let (arg_convert, args) = impl_arg_params(self, cls, true)?;
|
||||
let call = rust_call(args);
|
||||
let mut holders = Vec::new();
|
||||
let (arg_convert, args) = impl_arg_params(self, cls, true, &mut holders)?;
|
||||
let call = rust_call(args, &mut holders);
|
||||
quote! {
|
||||
unsafe fn #ident<'py>(
|
||||
py: _pyo3::Python<'py>,
|
||||
|
@ -566,13 +593,15 @@ impl<'a> FnSpec<'a> {
|
|||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||
#arg_convert
|
||||
#( #holders )*
|
||||
#call
|
||||
}
|
||||
}
|
||||
}
|
||||
CallingConvention::Varargs => {
|
||||
let (arg_convert, args) = impl_arg_params(self, cls, false)?;
|
||||
let call = rust_call(args);
|
||||
let mut holders = Vec::new();
|
||||
let (arg_convert, args) = impl_arg_params(self, cls, false, &mut holders)?;
|
||||
let call = rust_call(args, &mut holders);
|
||||
quote! {
|
||||
unsafe fn #ident<'py>(
|
||||
py: _pyo3::Python<'py>,
|
||||
|
@ -582,13 +611,15 @@ impl<'a> FnSpec<'a> {
|
|||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||
#arg_convert
|
||||
#( #holders )*
|
||||
#call
|
||||
}
|
||||
}
|
||||
}
|
||||
CallingConvention::TpNew => {
|
||||
let (arg_convert, args) = impl_arg_params(self, cls, false)?;
|
||||
let self_arg = self.tp.self_arg(cls, ExtractErrorMode::Raise);
|
||||
let mut holders = Vec::new();
|
||||
let (arg_convert, args) = impl_arg_params(self, cls, false, &mut holders)?;
|
||||
let self_arg = self.tp.self_arg(cls, ExtractErrorMode::Raise, &mut holders);
|
||||
let call = quote! { #rust_name(#self_arg #(#args),*) };
|
||||
quote! {
|
||||
unsafe fn #ident(
|
||||
|
@ -600,6 +631,7 @@ impl<'a> FnSpec<'a> {
|
|||
use _pyo3::callback::IntoPyCallbackOutput;
|
||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||
#arg_convert
|
||||
#( #holders )*
|
||||
let result = #call;
|
||||
let initializer: _pyo3::PyClassInitializer::<#cls> = result.convert(py)?;
|
||||
let cell = initializer.create_cell_from_subtype(py, _slf)?;
|
||||
|
|
|
@ -29,24 +29,23 @@ pub fn impl_arg_params(
|
|||
spec: &FnSpec<'_>,
|
||||
self_: Option<&syn::Type>,
|
||||
fastcall: bool,
|
||||
holders: &mut Vec<TokenStream>,
|
||||
) -> Result<(TokenStream, Vec<TokenStream>)> {
|
||||
let args_array = syn::Ident::new("output", Span::call_site());
|
||||
|
||||
if !fastcall && is_forwarded_args(&spec.signature) {
|
||||
// In the varargs convention, we can just pass though if the signature
|
||||
// is (*args, **kwds).
|
||||
let mut holders = Vec::new();
|
||||
let arg_convert = spec
|
||||
.signature
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|arg| impl_arg_param(arg, &mut 0, &args_array, &mut holders))
|
||||
.map(|arg| impl_arg_param(arg, &mut 0, &args_array, holders))
|
||||
.collect::<Result<_>>()?;
|
||||
return Ok((
|
||||
quote! {
|
||||
let _args = py.from_borrowed_ptr::<_pyo3::types::PyTuple>(_args);
|
||||
let _kwargs: ::std::option::Option<&_pyo3::types::PyDict> = py.from_borrowed_ptr_or_opt(_kwargs);
|
||||
#( #holders )*
|
||||
},
|
||||
arg_convert,
|
||||
));
|
||||
|
@ -75,12 +74,11 @@ pub fn impl_arg_params(
|
|||
let num_params = positional_parameter_names.len() + keyword_only_parameters.len();
|
||||
|
||||
let mut option_pos = 0;
|
||||
let mut holders = Vec::new();
|
||||
let param_conversion = spec
|
||||
.signature
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|arg| impl_arg_param(arg, &mut option_pos, &args_array, &mut holders))
|
||||
.map(|arg| impl_arg_param(arg, &mut option_pos, &args_array, holders))
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
let args_handler = if spec.signature.python_signature.varargs.is_some() {
|
||||
|
@ -134,7 +132,6 @@ pub fn impl_arg_params(
|
|||
keyword_only_parameters: &[#(#keyword_only_parameters),*],
|
||||
};
|
||||
let mut #args_array = [::std::option::Option::None; #num_params];
|
||||
#( #holders )*
|
||||
let (_args, _kwargs) = #extract_expression;
|
||||
},
|
||||
param_conversion,
|
||||
|
|
|
@ -481,9 +481,10 @@ fn impl_call_setter(
|
|||
cls: &syn::Type,
|
||||
spec: &FnSpec<'_>,
|
||||
self_type: &SelfType,
|
||||
holders: &mut Vec<TokenStream>,
|
||||
) -> syn::Result<TokenStream> {
|
||||
let (py_arg, args) = split_off_python_arg(&spec.signature.arguments);
|
||||
let slf = self_type.receiver(cls, ExtractErrorMode::Raise);
|
||||
let slf = self_type.receiver(cls, ExtractErrorMode::Raise, holders);
|
||||
|
||||
if args.is_empty() {
|
||||
bail_spanned!(spec.name.span() => "setter function expected to have one argument");
|
||||
|
@ -511,6 +512,7 @@ pub fn impl_py_setter_def(
|
|||
) -> Result<MethodAndMethodDef> {
|
||||
let python_name = property_type.null_terminated_python_name()?;
|
||||
let doc = property_type.doc();
|
||||
let mut holders = Vec::new();
|
||||
let setter_impl = match property_type {
|
||||
PropertyType::Descriptor {
|
||||
field_index, field, ..
|
||||
|
@ -519,7 +521,7 @@ pub fn impl_py_setter_def(
|
|||
mutable: true,
|
||||
span: Span::call_site(),
|
||||
}
|
||||
.receiver(cls, ExtractErrorMode::Raise);
|
||||
.receiver(cls, ExtractErrorMode::Raise, &mut holders);
|
||||
if let Some(ident) = &field.ident {
|
||||
// named struct field
|
||||
quote!({ #slf.#ident = _val; })
|
||||
|
@ -531,7 +533,7 @@ pub fn impl_py_setter_def(
|
|||
}
|
||||
PropertyType::Function {
|
||||
spec, self_type, ..
|
||||
} => impl_call_setter(cls, spec, self_type)?,
|
||||
} => impl_call_setter(cls, spec, self_type, &mut holders)?,
|
||||
};
|
||||
|
||||
let wrapper_ident = match property_type {
|
||||
|
@ -575,7 +577,7 @@ pub fn impl_py_setter_def(
|
|||
_pyo3::exceptions::PyAttributeError::new_err("can't delete attribute")
|
||||
})?;
|
||||
let _val = _pyo3::FromPyObject::extract(_value)?;
|
||||
|
||||
#( #holders )*
|
||||
_pyo3::callback::convert(py, #setter_impl)
|
||||
}
|
||||
};
|
||||
|
@ -601,9 +603,10 @@ fn impl_call_getter(
|
|||
cls: &syn::Type,
|
||||
spec: &FnSpec<'_>,
|
||||
self_type: &SelfType,
|
||||
holders: &mut Vec<TokenStream>,
|
||||
) -> syn::Result<TokenStream> {
|
||||
let (py_arg, args) = split_off_python_arg(&spec.signature.arguments);
|
||||
let slf = self_type.receiver(cls, ExtractErrorMode::Raise);
|
||||
let slf = self_type.receiver(cls, ExtractErrorMode::Raise, holders);
|
||||
ensure_spanned!(
|
||||
args.is_empty(),
|
||||
args[0].ty.span() => "getter function can only have one argument (of type pyo3::Python)"
|
||||
|
@ -627,6 +630,7 @@ pub fn impl_py_getter_def(
|
|||
let python_name = property_type.null_terminated_python_name()?;
|
||||
let doc = property_type.doc();
|
||||
|
||||
let mut holders = Vec::new();
|
||||
let body = match property_type {
|
||||
PropertyType::Descriptor {
|
||||
field_index, field, ..
|
||||
|
@ -635,7 +639,7 @@ pub fn impl_py_getter_def(
|
|||
mutable: false,
|
||||
span: Span::call_site(),
|
||||
}
|
||||
.receiver(cls, ExtractErrorMode::Raise);
|
||||
.receiver(cls, ExtractErrorMode::Raise, &mut holders);
|
||||
let field_token = if let Some(ident) = &field.ident {
|
||||
// named struct field
|
||||
ident.to_token_stream()
|
||||
|
@ -651,7 +655,7 @@ pub fn impl_py_getter_def(
|
|||
PropertyType::Function {
|
||||
spec, self_type, ..
|
||||
} => {
|
||||
let call = impl_call_getter(cls, spec, self_type)?;
|
||||
let call = impl_call_getter(cls, spec, self_type, &mut holders)?;
|
||||
quote! {
|
||||
_pyo3::callback::convert(py, #call)
|
||||
}
|
||||
|
@ -692,6 +696,7 @@ pub fn impl_py_getter_def(
|
|||
py: _pyo3::Python<'_>,
|
||||
_slf: *mut _pyo3::ffi::PyObject
|
||||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||
#( #holders )*
|
||||
#body
|
||||
}
|
||||
};
|
||||
|
@ -1154,7 +1159,7 @@ fn generate_method_body(
|
|||
holders: &mut Vec<TokenStream>,
|
||||
return_mode: Option<&ReturnMode>,
|
||||
) -> Result<TokenStream> {
|
||||
let self_arg = spec.tp.self_arg(Some(cls), extract_error_mode);
|
||||
let self_arg = spec.tp.self_arg(Some(cls), extract_error_mode, holders);
|
||||
let rust_name = spec.name;
|
||||
let args = extract_proto_arguments(spec, arguments, extract_error_mode, holders)?;
|
||||
let call = quote! { _pyo3::callback::convert(py, #cls::#rust_name(#self_arg #(#args),*)) };
|
||||
|
|
Loading…
Reference in New Issue