Skip to content

Commit 4d7dfaf

Browse files
committed
Allow slf: &PyClassShell<Self>
1 parent bdb66af commit 4d7dfaf

File tree

2 files changed

+26
-19
lines changed

2 files changed

+26
-19
lines changed

pyo3-derive-backend/src/method.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub enum FnType {
2727
FnCall,
2828
FnClass,
2929
FnStatic,
30-
PySelf(syn::TypePath),
30+
PySelfNew(syn::TypeReference),
3131
}
3232

3333
#[derive(Clone, PartialEq, Debug)]
@@ -103,13 +103,16 @@ impl<'a> FnSpec<'a> {
103103

104104
if fn_type == FnType::Fn && !has_self {
105105
if arguments.is_empty() {
106-
panic!("Static method needs #[staticmethod] attribute");
106+
return Err(syn::Error::new_spanned(
107+
name,
108+
"Static method needs #[staticmethod] attribute",
109+
));
107110
}
108111
let tp = match arguments.remove(0).ty {
109-
syn::Type::Path(p) => replace_self(p),
110-
_ => panic!("Invalid type as self"),
112+
syn::Type::Reference(r) => replace_self(r)?,
113+
x => return Err(syn::Error::new_spanned(x, "Invalid type as custom self")),
111114
};
112-
fn_type = FnType::PySelf(tp);
115+
fn_type = FnType::PySelfNew(tp);
113116
}
114117

115118
Ok(FnSpec {
@@ -386,15 +389,19 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> syn::Result<(FnType, Vec
386389
}
387390
}
388391

389-
// Replace A<Self> with A<_>
390-
fn replace_self(path: &syn::TypePath) -> syn::TypePath {
392+
// Replace &A<Self> with &A<_>
393+
fn replace_self(refn: &syn::TypeReference) -> syn::Result<syn::TypeReference> {
391394
fn infer(span: proc_macro2::Span) -> syn::GenericArgument {
392395
syn::GenericArgument::Type(syn::Type::Infer(syn::TypeInfer {
393396
underscore_token: syn::token::Underscore { spans: [span] },
394397
}))
395398
}
396-
let mut res = path.to_owned();
397-
for seg in &mut res.path.segments {
399+
let mut res = refn.to_owned();
400+
let tp = match &mut *res.elem {
401+
syn::Type::Path(p) => p,
402+
_ => return Err(syn::Error::new_spanned(refn, "unsupported argument")),
403+
};
404+
for seg in &mut tp.path.segments {
398405
if let syn::PathArguments::AngleBracketed(ref mut g) = seg.arguments {
399406
let mut args = syn::punctuated::Punctuated::new();
400407
for arg in &g.args {
@@ -415,5 +422,6 @@ fn replace_self(path: &syn::TypePath) -> syn::TypePath {
415422
g.args = args;
416423
}
417424
}
418-
res
425+
res.lifetime = None;
426+
Ok(res)
419427
}

pyo3-derive-backend/src/pymethod.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn gen_py_method(
3434
};
3535

3636
let text_signature = match &spec.tp {
37-
FnType::Fn | FnType::PySelf(_) | FnType::FnClass | FnType::FnStatic => {
37+
FnType::Fn | FnType::PySelfNew(_) | FnType::FnClass | FnType::FnStatic => {
3838
utils::parse_text_signature_attrs(&mut *meth_attrs, name)?
3939
}
4040
FnType::FnNew => parse_erroneous_text_signature(
@@ -59,7 +59,7 @@ pub fn gen_py_method(
5959

6060
Ok(match spec.tp {
6161
FnType::Fn => impl_py_method_def(name, doc, &spec, &impl_wrap(cls, name, &spec, true)),
62-
FnType::PySelf(ref self_ty) => impl_py_method_def(
62+
FnType::PySelfNew(ref self_ty) => impl_py_method_def(
6363
name,
6464
doc,
6565
&spec,
@@ -127,7 +127,7 @@ pub fn impl_wrap_pyslf(
127127
cls: &syn::Type,
128128
name: &syn::Ident,
129129
spec: &FnSpec<'_>,
130-
self_ty: &syn::TypePath,
130+
self_ty: &syn::TypeReference,
131131
noargs: bool,
132132
) -> TokenStream {
133133
let names = get_arg_names(spec);
@@ -221,8 +221,7 @@ pub fn impl_proto_wrap(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec<'_>) ->
221221
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
222222
pub fn impl_wrap_new(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec<'_>) -> TokenStream {
223223
let names: Vec<syn::Ident> = get_arg_names(&spec);
224-
let cb = quote! { #cls::#name(&_obj, #(#names),*) };
225-
224+
let cb = quote! { #cls::#name(#(#names),*) };
226225
let body = impl_arg_params(spec, cb);
227226

228227
quote! {
@@ -240,11 +239,11 @@ pub fn impl_wrap_new(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec<'_>) -> T
240239
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
241240
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
242241

243-
#body
242+
# body
244243

245-
match <<#cls as pyo3::PyTypeInfo>::ConcreteLayout as pyo3::pyclass::PyClassNew>::new(_py, _result) {
246-
Ok(_slf) => _slf as _,
247-
Err(e) => e.restore_and_null(),
244+
match _result.and_then(|slf| pyo3::PyClassShell::new(_py, slf)) {
245+
Ok(slf) => slf as _,
246+
Err(e) => e.restore_and_null(_py),
248247
}
249248
}
250249
}

0 commit comments

Comments
 (0)