Skip to content

Commit fca4b21

Browse files
committed
fix error with named lifetimes in #[new] return types
1 parent 999560a commit fca4b21

5 files changed

Lines changed: 33 additions & 19 deletions

File tree

newsfragments/5998.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fixed compilation error for `#[new]` return types that contain named lifetimes

pyo3-macros-backend/src/py_expr.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use proc_macro2::TokenStream;
55
use quote::quote;
66
use std::borrow::Cow;
77
use syn::visit_mut::{visit_type_mut, VisitMut};
8-
use syn::{Expr, ExprLit, ExprPath, Lifetime, Lit, Type};
8+
use syn::{Expr, ExprLit, ExprPath, Lit, Type};
99

1010
/// A Python expression
1111
///
@@ -268,26 +268,10 @@ fn clean_type(mut t: Type, self_type: Option<&Type>) -> Type {
268268
if let Some(self_type) = self_type {
269269
replace_self(&mut t, self_type);
270270
}
271-
elide_lifetimes(&mut t);
271+
crate::utils::elide_lifetimes(&mut t);
272272
t
273273
}
274274

275-
/// Replaces all explicit lifetimes in `self` with elided (`'_`) lifetimes
276-
///
277-
/// This is useful if `Self` is used in `const` context, where explicit
278-
/// lifetimes are not allowed (yet).
279-
fn elide_lifetimes(ty: &mut Type) {
280-
struct ElideLifetimesVisitor;
281-
282-
impl VisitMut for ElideLifetimesVisitor {
283-
fn visit_lifetime_mut(&mut self, l: &mut Lifetime) {
284-
*l = Lifetime::new("'_", l.span());
285-
}
286-
}
287-
288-
ElideLifetimesVisitor.visit_type_mut(ty);
289-
}
290-
291275
// Replace Self in types with the given type
292276
fn replace_self(ty: &mut Type, self_target: &Type) {
293277
struct SelfReplacementVisitor<'a> {

pyo3-macros-backend/src/pymethod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1474,9 +1474,11 @@ fn generate_method_body(
14741474
});
14751475

14761476
let output = if let syn::ReturnType::Type(_, ty) = &spec.output {
1477+
let mut ty = ty.clone();
1478+
utils::elide_lifetimes(&mut ty);
14771479
ty
14781480
} else {
1479-
&parse_quote!(())
1481+
parse_quote!(())
14801482
};
14811483
let body = quote! {
14821484
#text_signature_impl

pyo3-macros-backend/src/utils.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,3 +375,19 @@ pub(crate) fn locate_tokens_at(tokens: TokenStream, span: Span) -> TokenStream {
375375
let output_span = tokens.span().located_at(span);
376376
set_span_recursively(tokens, output_span)
377377
}
378+
379+
/// Replaces all explicit lifetimes in `self` with elided (`'_`) lifetimes
380+
///
381+
/// This is useful if `Self` is used in `const` context, where explicit
382+
/// lifetimes are not allowed (yet).
383+
pub(crate) fn elide_lifetimes(ty: &mut syn::Type) {
384+
struct ElideLifetimesVisitor;
385+
386+
impl syn::visit_mut::VisitMut for ElideLifetimesVisitor {
387+
fn visit_lifetime_mut(&mut self, l: &mut syn::Lifetime) {
388+
*l = syn::Lifetime::new("'_", l.span());
389+
}
390+
}
391+
392+
syn::visit_mut::VisitMut::visit_type_mut(&mut ElideLifetimesVisitor, ty);
393+
}

src/tests/hygiene/pymethods.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,3 +566,14 @@ impl WarningDummy2 {
566566
#[pyo3(warn(message = "this class-method raises user-defined warning", category = UserDefinedWarning))]
567567
fn multiple_warnings_fn_with_custom_category(&self) {}
568568
}
569+
570+
#[crate::pyclass(crate = "crate")]
571+
struct NewReturnsNamedLifetime;
572+
573+
#[crate::pymethods(crate = "crate")]
574+
impl NewReturnsNamedLifetime {
575+
#[new]
576+
fn new<'py>(py: crate::Python<'py>) -> crate::PyResult<crate::Bound<'py, Self>> {
577+
crate::Bound::new(py, Self)
578+
}
579+
}

0 commit comments

Comments
 (0)