From 0187cc58d1adc7f93b0c1ee9440aa0940299f3b5 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 23 Jul 2026 02:54:32 +0000 Subject: [PATCH 15/25] hir_conv: elide output lifetimes through arbitrary self types The output-lifetime elision rule only recognised a receiver whose type was a direct borrow (`&self`/`&mut self`). For arbitrary self types like `self: Pin<&mut Self>` no candidate was found, and with multiple input lifetimes the elided return lifetime then hit "Unspecified lifetime in outer context". rustc's self-elision looks through the receiver type for references to `Self`; mirror that: when the receiver isn't a direct borrow, search it for `&Self` borrows and use the lifetime if exactly one is found. Seen with futures-io 0.3.32: fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_013wCVW89GjmNyYviEcANPHM --- src/hir_conv/lifetime_elision.cpp | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/hir_conv/lifetime_elision.cpp b/src/hir_conv/lifetime_elision.cpp index ce8e9f1c..33c72e0d 100644 --- a/src/hir_conv/lifetime_elision.cpp +++ b/src/hir_conv/lifetime_elision.cpp @@ -1115,6 +1115,40 @@ namespace elided_output_lifetime = b->lifetime; } } + else { + // Arbitrary self types (e.g. `self: Pin<&mut Self>`, futures-io's + // `fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>`): + // rustc's self-elision rule looks through the receiver type for + // references to `Self` - if there is exactly one, its lifetime is + // assigned to elided output lifetimes. + struct SelfBorrowV: public HIR::Visitor { + const ::HIR::TypeRef* self_type; + HIR::LifetimeRef out; + unsigned n_found = 0; + bool is_self(const HIR::TypeRef& ty) const { + if( ty.data().is_Generic() && ty.data().as_Generic().is_self() ) + return true; + if( self_type && ty == *self_type ) + return true; + return false; + } + void visit_type(HIR::TypeRef& ty) override { + if(const auto* tep = ty.data().opt_Borrow()) { + if( is_self(tep->inner) ) { + n_found += 1; + out = tep->lifetime; + } + } + HIR::Visitor::visit_type(ty); + } + } v; + v.self_type = m_resolve.m_self_type; + v.visit_type(item.m_args[0].second); + if( v.n_found == 1 ) { + elided_output_lifetime = v.out; + DEBUG("Elided/explicit 'self (through receiver) - " << elided_output_lifetime); + } + } if( item.m_receiver == HIR::Function::Receiver::Value ) { m_value_self_type = m_resolve.m_self_type; } -- 2.43.0