Skip to content

Commit 220a6ac

Browse files
committed
Allow reborrowing Pin<&mut Self>
1 parent a18800f commit 220a6ac

File tree

4 files changed

+75
-21
lines changed

4 files changed

+75
-21
lines changed

compiler/rustc_hir_typeck/src/method/confirm.rs

+9
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
235235
target,
236236
});
237237
}
238+
239+
Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
240+
let region = self.next_region_var(infer::Autoref(self.span));
241+
242+
adjustments.push(Adjustment {
243+
kind: Adjust::ReborrowPin(region, mutbl),
244+
target,
245+
});
246+
}
238247
None => {}
239248
}
240249

compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs

+26-6
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
121121
mutbl.ref_prefix_str()
122122
}
123123
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
124+
Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
125+
hir::Mutability::Mut => "Pin<&mut ",
126+
hir::Mutability::Not => "Pin<&",
127+
},
124128
};
125129
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
126130
{
127-
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
131+
let mut self_adjusted =
132+
if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
133+
pick.autoref_or_ptr_adjustment
134+
{
135+
format!("{derefs}{self_expr} as *const _")
136+
} else {
137+
format!("{autoref}{derefs}{self_expr}")
138+
};
139+
140+
if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) =
128141
pick.autoref_or_ptr_adjustment
129142
{
130-
format!("{derefs}{self_expr} as *const _")
131-
} else {
132-
format!("{autoref}{derefs}{self_expr}")
133-
};
143+
self_adjusted.push('>');
144+
}
134145

135146
lint.span_suggestion(
136147
sp,
@@ -400,6 +411,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
400411
let autoref = match pick.autoref_or_ptr_adjustment {
401412
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(),
402413
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
414+
Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
415+
hir::Mutability::Mut => "Pin<&mut ",
416+
hir::Mutability::Not => "Pin<&",
417+
},
403418
};
404419

405420
let (expr_text, precise) = if let Some(expr_text) = expr
@@ -412,14 +427,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
412427
("(..)".to_string(), false)
413428
};
414429

415-
let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
430+
let mut adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
416431
pick.autoref_or_ptr_adjustment
417432
{
418433
format!("{derefs}{expr_text} as *const _")
419434
} else {
420435
format!("{autoref}{derefs}{expr_text}")
421436
};
422437

438+
if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = pick.autoref_or_ptr_adjustment
439+
{
440+
adjusted_text.push('>');
441+
}
442+
423443
(adjusted_text, precise)
424444
}
425445
}

compiler/rustc_hir_typeck/src/method/probe.rs

+25-10
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ use std::ops::Deref;
55

66
use rustc_data_structures::fx::FxHashSet;
77
use rustc_errors::Applicability;
8-
use rustc_hir as hir;
98
use rustc_hir::def::DefKind;
10-
use rustc_hir::HirId;
9+
use rustc_hir::{self as hir, HirId};
1110
use rustc_hir_analysis::autoderef::{self, Autoderef};
1211
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
1312
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, TyCtxtInferExt};
@@ -136,7 +135,7 @@ enum ProbeResult {
136135
/// `mut`), or it has type `*mut T` and we convert it to `*const T`.
137136
#[derive(Debug, PartialEq, Copy, Clone)]
138137
pub(crate) enum AutorefOrPtrAdjustment {
139-
/// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
138+
/// Receiver has type `T`, add `&` or `&mut` (if `T` is `mut`), and maybe also "unsize" it.
140139
/// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
141140
Autoref {
142141
mutbl: hir::Mutability,
@@ -147,13 +146,17 @@ pub(crate) enum AutorefOrPtrAdjustment {
147146
},
148147
/// Receiver has type `*mut T`, convert to `*const T`
149148
ToConstPtr,
149+
150+
/// Reborrow a `Pin<&mut T>` or `Pin<&T>`.
151+
ReborrowPin(hir::Mutability),
150152
}
151153

152154
impl AutorefOrPtrAdjustment {
153155
fn get_unsize(&self) -> bool {
154156
match self {
155157
AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
156158
AutorefOrPtrAdjustment::ToConstPtr => false,
159+
AutorefOrPtrAdjustment::ReborrowPin(_) => false,
157160
}
158161
}
159162
}
@@ -1123,13 +1126,25 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11231126
r.map(|mut pick| {
11241127
pick.autoderefs = step.autoderefs;
11251128

1126-
// Insert a `&*` or `&mut *` if this is a reference type:
1127-
if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() {
1128-
pick.autoderefs += 1;
1129-
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
1130-
mutbl,
1131-
unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
1132-
})
1129+
match *step.self_ty.value.value.kind() {
1130+
// Insert a `&*` or `&mut *` if this is a reference type:
1131+
ty::Ref(_, _, mutbl) => {
1132+
pick.autoderefs += 1;
1133+
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
1134+
mutbl,
1135+
unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
1136+
})
1137+
}
1138+
1139+
ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => {
1140+
// make sure this is a pinned reference (and not a `Pin<Box>` or something)
1141+
if let ty::Ref(_, _, mutbl) = args[0].expect_ty().kind() {
1142+
pick.autoref_or_ptr_adjustment =
1143+
Some(AutorefOrPtrAdjustment::ReborrowPin(*mutbl));
1144+
}
1145+
}
1146+
1147+
_ => (),
11331148
}
11341149

11351150
pick
+15-5
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,34 @@
11
//@ check-pass
2-
//@ignore-test
3-
4-
// Currently ignored due to self reborrowing not being implemented for Pin
52

63
#![feature(pin_ergonomics)]
74
#![allow(incomplete_features)]
85

96
use std::pin::Pin;
107

11-
struct Foo;
8+
pub struct Foo;
129

1310
impl Foo {
1411
fn foo(self: Pin<&mut Self>) {
1512
}
13+
14+
fn baz(self: Pin<&Self>) {
15+
}
1616
}
1717

18-
fn bar(x: Pin<&mut Foo>) {
18+
pub fn bar(x: Pin<&mut Foo>) {
1919
x.foo();
2020
x.foo(); // for this to work we need to automatically reborrow,
2121
// as if the user had written `x.as_mut().foo()`.
22+
23+
Foo::baz(x);
24+
25+
// FIXME: We should allow downgrading a Pin<&mut T> to Pin<&T>
26+
// x.baz();
27+
}
28+
29+
pub fn baaz(x: Pin<&Foo>) {
30+
x.baz();
31+
x.baz();
2232
}
2333

2434
fn main() {}

0 commit comments

Comments
 (0)