Allow reborrowing Pin<&mut Self>

This commit is contained in:
Eric Holk 2024-09-19 17:23:46 -07:00
parent c22a4215a0
commit 97fbcf6773
No known key found for this signature in database
GPG Key ID: F1A772BB658A63E1
4 changed files with 74 additions and 19 deletions

View File

@ -235,6 +235,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
target,
});
}
Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
let region = self.next_region_var(infer::Autoref(self.span));
adjustments.push(Adjustment {
kind: Adjust::ReborrowPin(region, mutbl),
target,
});
}
None => {}
}

View File

@ -121,16 +121,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mutbl.ref_prefix_str()
}
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
hir::Mutability::Mut => "Pin<&mut ",
hir::Mutability::Not => "Pin<&",
},
};
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
{
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
let mut self_adjusted =
if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
pick.autoref_or_ptr_adjustment
{
format!("{derefs}{self_expr} as *const _")
} else {
format!("{autoref}{derefs}{self_expr}")
};
if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) =
pick.autoref_or_ptr_adjustment
{
format!("{derefs}{self_expr} as *const _")
} else {
format!("{autoref}{derefs}{self_expr}")
};
self_adjusted.push('>');
}
lint.span_suggestion(
sp,
@ -400,6 +411,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let autoref = match pick.autoref_or_ptr_adjustment {
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(),
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
hir::Mutability::Mut => "Pin<&mut ",
hir::Mutability::Not => "Pin<&",
},
};
let (expr_text, precise) = if let Some(expr_text) = expr
@ -412,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
("(..)".to_string(), false)
};
let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
let mut adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
pick.autoref_or_ptr_adjustment
{
format!("{derefs}{expr_text} as *const _")
@ -420,6 +435,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("{autoref}{derefs}{expr_text}")
};
if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = pick.autoref_or_ptr_adjustment
{
adjusted_text.push('>');
}
(adjusted_text, precise)
}
}

View File

@ -136,7 +136,7 @@ enum ProbeResult {
/// `mut`), or it has type `*mut T` and we convert it to `*const T`.
#[derive(Debug, PartialEq, Copy, Clone)]
pub(crate) enum AutorefOrPtrAdjustment {
/// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
/// Receiver has type `T`, add `&` or `&mut` (if `T` is `mut`), and maybe also "unsize" it.
/// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
Autoref {
mutbl: hir::Mutability,
@ -147,6 +147,9 @@ pub(crate) enum AutorefOrPtrAdjustment {
},
/// Receiver has type `*mut T`, convert to `*const T`
ToConstPtr,
/// Reborrow a `Pin<&mut T>` or `Pin<&T>`.
ReborrowPin(hir::Mutability),
}
impl AutorefOrPtrAdjustment {
@ -154,6 +157,7 @@ impl AutorefOrPtrAdjustment {
match self {
AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
AutorefOrPtrAdjustment::ToConstPtr => false,
AutorefOrPtrAdjustment::ReborrowPin(_) => false,
}
}
}
@ -1133,13 +1137,25 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
// Insert a `&*` or `&mut *` if this is a reference type:
if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() {
pick.autoderefs += 1;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
mutbl,
unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
})
match *step.self_ty.value.value.kind() {
// Insert a `&*` or `&mut *` if this is a reference type:
ty::Ref(_, _, mutbl) => {
pick.autoderefs += 1;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
mutbl,
unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
})
}
ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => {
// make sure this is a pinned reference (and not a `Pin<Box>` or something)
if let ty::Ref(_, _, mutbl) = args[0].expect_ty().kind() {
pick.autoref_or_ptr_adjustment =
Some(AutorefOrPtrAdjustment::ReborrowPin(*mutbl));
}
}
_ => (),
}
pick

View File

@ -1,24 +1,34 @@
//@ check-pass
//@ignore-test
// Currently ignored due to self reborrowing not being implemented for Pin
#![feature(pin_ergonomics)]
#![allow(incomplete_features)]
use std::pin::Pin;
struct Foo;
pub struct Foo;
impl Foo {
fn foo(self: Pin<&mut Self>) {
}
fn baz(self: Pin<&Self>) {
}
}
fn bar(x: Pin<&mut Foo>) {
pub fn bar(x: Pin<&mut Foo>) {
x.foo();
x.foo(); // for this to work we need to automatically reborrow,
// as if the user had written `x.as_mut().foo()`.
Foo::baz(x);
// FIXME: We should allow downgrading a Pin<&mut T> to Pin<&T>
// x.baz();
}
pub fn baaz(x: Pin<&Foo>) {
x.baz();
x.baz();
}
fn main() {}