Skip to content

Commit a59f77a

Browse files
authored
Unrolled build for rust-lang#130633
Rollup merge of rust-lang#130633 - eholk:pin-reborrow-self, r=compiler-errors Add support for reborrowing pinned method receivers This builds on rust-lang#130526 to add pinned reborrowing for method receivers. This enables the folllowing examples to work: ```rust #![feature(pin_ergonomics)] #![allow(incomplete_features)] use std::pin::Pin; pub struct Foo; impl Foo { fn foo(self: Pin<&mut Self>) { } fn baz(self: Pin<&Self>) { } } pub fn bar(x: Pin<&mut Foo>) { x.foo(); x.foo(); x.baz(); // Pin<&mut Foo> is downgraded to Pin<&Foo> } pub fn baaz(x: Pin<&Foo>) { x.baz(); x.baz(); } ``` This PR includes the original one, which is currently in the commit queue, but the only code changes are in the latest commit (d3c53aa). rust-lang#130494 r? `@compiler-errors`
2 parents 495f75a + 9b52fb5 commit a59f77a

File tree

7 files changed

+171
-22
lines changed

7 files changed

+171
-22
lines changed

compiler/rustc_hir_typeck/src/method/confirm.rs

+17
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,23 @@ 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+
target = match target.kind() {
243+
ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
244+
let inner_ty = match args[0].expect_ty().kind() {
245+
ty::Ref(_, ty, _) => *ty,
246+
_ => bug!("Expected a reference type for argument to Pin"),
247+
};
248+
Ty::new_pinned_ref(self.tcx, region, inner_ty, mutbl)
249+
}
250+
_ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"),
251+
};
252+
253+
adjustments.push(Adjustment { kind: Adjust::ReborrowPin(region, mutbl), target });
254+
}
238255
None => {}
239256
}
240257

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

+71-8
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ enum ProbeResult {
136136
/// `mut`), or it has type `*mut T` and we convert it to `*const T`.
137137
#[derive(Debug, PartialEq, Copy, Clone)]
138138
pub(crate) enum AutorefOrPtrAdjustment {
139-
/// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
139+
/// Receiver has type `T`, add `&` or `&mut` (if `T` is `mut`), and maybe also "unsize" it.
140140
/// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
141141
Autoref {
142142
mutbl: hir::Mutability,
@@ -147,13 +147,17 @@ pub(crate) enum AutorefOrPtrAdjustment {
147147
},
148148
/// Receiver has type `*mut T`, convert to `*const T`
149149
ToConstPtr,
150+
151+
/// Reborrow a `Pin<&mut T>` or `Pin<&T>`.
152+
ReborrowPin(hir::Mutability),
150153
}
151154

152155
impl AutorefOrPtrAdjustment {
153156
fn get_unsize(&self) -> bool {
154157
match self {
155158
AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
156159
AutorefOrPtrAdjustment::ToConstPtr => false,
160+
AutorefOrPtrAdjustment::ReborrowPin(_) => false,
157161
}
158162
}
159163
}
@@ -1103,6 +1107,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11031107
unstable_candidates.as_deref_mut(),
11041108
)
11051109
})
1110+
.or_else(|| {
1111+
self.pick_reborrow_pin_method(
1112+
step,
1113+
self_ty,
1114+
unstable_candidates.as_deref_mut(),
1115+
)
1116+
})
11061117
})
11071118
})
11081119
}
@@ -1127,13 +1138,28 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11271138
r.map(|mut pick| {
11281139
pick.autoderefs = step.autoderefs;
11291140

1130-
// Insert a `&*` or `&mut *` if this is a reference type:
1131-
if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() {
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-
})
1141+
match *step.self_ty.value.value.kind() {
1142+
// Insert a `&*` or `&mut *` if this is a reference type:
1143+
ty::Ref(_, _, mutbl) => {
1144+
pick.autoderefs += 1;
1145+
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
1146+
mutbl,
1147+
unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
1148+
})
1149+
}
1150+
1151+
ty::Adt(def, args)
1152+
if self.tcx.features().pin_ergonomics
1153+
&& self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) =>
1154+
{
1155+
// make sure this is a pinned reference (and not a `Pin<Box>` or something)
1156+
if let ty::Ref(_, _, mutbl) = args[0].expect_ty().kind() {
1157+
pick.autoref_or_ptr_adjustment =
1158+
Some(AutorefOrPtrAdjustment::ReborrowPin(*mutbl));
1159+
}
1160+
}
1161+
1162+
_ => (),
11371163
}
11381164

11391165
pick
@@ -1164,6 +1190,43 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11641190
})
11651191
}
11661192

1193+
/// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`.
1194+
#[instrument(level = "debug", skip(self, step, unstable_candidates))]
1195+
fn pick_reborrow_pin_method(
1196+
&self,
1197+
step: &CandidateStep<'tcx>,
1198+
self_ty: Ty<'tcx>,
1199+
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1200+
) -> Option<PickResult<'tcx>> {
1201+
if !self.tcx.features().pin_ergonomics {
1202+
return None;
1203+
}
1204+
1205+
// make sure self is a Pin<&mut T>
1206+
let inner_ty = match self_ty.kind() {
1207+
ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => {
1208+
match args[0].expect_ty().kind() {
1209+
ty::Ref(_, ty, hir::Mutability::Mut) => *ty,
1210+
_ => {
1211+
return None;
1212+
}
1213+
}
1214+
}
1215+
_ => return None,
1216+
};
1217+
1218+
let region = self.tcx.lifetimes.re_erased;
1219+
let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
1220+
self.pick_method(autopin_ty, unstable_candidates).map(|r| {
1221+
r.map(|mut pick| {
1222+
pick.autoderefs = step.autoderefs;
1223+
pick.autoref_or_ptr_adjustment =
1224+
Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
1225+
pick
1226+
})
1227+
})
1228+
}
1229+
11671230
/// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
11681231
/// special case for this is because going from `*mut T` to `*const T` with autoderefs and
11691232
/// autorefs would require dereferencing the pointer, which is not safe.

compiler/rustc_middle/src/ty/sty.rs

+10
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,16 @@ impl<'tcx> Ty<'tcx> {
584584
Ty::new_ref(tcx, r, ty, hir::Mutability::Not)
585585
}
586586

587+
pub fn new_pinned_ref(
588+
tcx: TyCtxt<'tcx>,
589+
r: Region<'tcx>,
590+
ty: Ty<'tcx>,
591+
mutbl: ty::Mutability,
592+
) -> Ty<'tcx> {
593+
let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None));
594+
Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()]))
595+
}
596+
587597
#[inline]
588598
pub fn new_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mutbl: ty::Mutability) -> Ty<'tcx> {
589599
Ty::new(tcx, ty::RawPtr(ty, mutbl))
+14-5
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,33 @@
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+
x.baz();
26+
}
27+
28+
pub fn baaz(x: Pin<&Foo>) {
29+
x.baz();
30+
x.baz();
2231
}
2332

2433
fn main() {}

tests/ui/feature-gates/feature-gate-pin_ergonomics.rs

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ use std::pin::Pin;
44

55
struct Foo;
66

7+
impl Foo {
8+
fn foo(self: Pin<&mut Self>) {
9+
}
10+
}
11+
712
fn foo(_: Pin<&mut Foo>) {
813
}
914

@@ -12,4 +17,9 @@ fn bar(mut x: Pin<&mut Foo>) {
1217
foo(x); //~ ERROR use of moved value: `x`
1318
}
1419

20+
fn baz(mut x: Pin<&mut Foo>) {
21+
x.foo();
22+
x.foo(); //~ ERROR use of moved value: `x`
23+
}
24+
1525
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0382]: use of moved value: `x`
2-
--> $DIR/feature-gate-pin_ergonomics.rs:12:9
2+
--> $DIR/feature-gate-pin_ergonomics.rs:17:9
33
|
44
LL | fn bar(mut x: Pin<&mut Foo>) {
55
| ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
@@ -9,13 +9,33 @@ LL | foo(x);
99
| ^ value used here after move
1010
|
1111
note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary
12-
--> $DIR/feature-gate-pin_ergonomics.rs:7:11
12+
--> $DIR/feature-gate-pin_ergonomics.rs:12:11
1313
|
1414
LL | fn foo(_: Pin<&mut Foo>) {
1515
| --- ^^^^^^^^^^^^^ this parameter takes ownership of the value
1616
| |
1717
| in this function
1818

19-
error: aborting due to 1 previous error
19+
error[E0382]: use of moved value: `x`
20+
--> $DIR/feature-gate-pin_ergonomics.rs:22:5
21+
|
22+
LL | fn baz(mut x: Pin<&mut Foo>) {
23+
| ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
24+
LL | x.foo();
25+
| ----- `x` moved due to this method call
26+
LL | x.foo();
27+
| ^ value used here after move
28+
|
29+
note: `Foo::foo` takes ownership of the receiver `self`, which moves `x`
30+
--> $DIR/feature-gate-pin_ergonomics.rs:8:12
31+
|
32+
LL | fn foo(self: Pin<&mut Self>) {
33+
| ^^^^
34+
help: consider reborrowing the `Pin` instead of moving it
35+
|
36+
LL | x.as_mut().foo();
37+
| +++++++++
38+
39+
error: aborting due to 2 previous errors
2040

2141
For more information about this error, try `rustc --explain E0382`.

0 commit comments

Comments
 (0)