Skip to content

Commit 3dfb30c

Browse files
committed
Allow reborrowing pinned self methods
1 parent 97fbcf6 commit 3dfb30c

File tree

6 files changed

+123
-10
lines changed

6 files changed

+123
-10
lines changed

compiler/rustc_hir_typeck/src/method/confirm.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
239239
Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
240240
let region = self.next_region_var(infer::Autoref(self.span));
241241

242-
adjustments.push(Adjustment {
243-
kind: Adjust::ReborrowPin(region, mutbl),
244-
target,
245-
});
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 });
246254
}
247255
None => {}
248256
}

compiler/rustc_hir_typeck/src/method/probe.rs

+48-1
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11131113
unstable_candidates.as_deref_mut(),
11141114
)
11151115
})
1116+
.or_else(|| {
1117+
self.pick_reborrow_pin_method(
1118+
step,
1119+
self_ty,
1120+
unstable_candidates.as_deref_mut(),
1121+
)
1122+
})
11161123
})
11171124
})
11181125
}
@@ -1147,7 +1154,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11471154
})
11481155
}
11491156

1150-
ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => {
1157+
ty::Adt(def, args)
1158+
if self.tcx.features().pin_ergonomics
1159+
&& self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) =>
1160+
{
11511161
// make sure this is a pinned reference (and not a `Pin<Box>` or something)
11521162
if let ty::Ref(_, _, mutbl) = args[0].expect_ty().kind() {
11531163
pick.autoref_or_ptr_adjustment =
@@ -1186,6 +1196,43 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11861196
})
11871197
}
11881198

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

tests/ui/async-await/pin-reborrow-self.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ pub fn bar(x: Pin<&mut Foo>) {
2222

2323
Foo::baz(x);
2424

25-
// FIXME: We should allow downgrading a Pin<&mut T> to Pin<&T>
26-
// x.baz();
25+
x.baz();
2726
}
2827

2928
pub fn baaz(x: Pin<&Foo>) {

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

+8
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,20 @@ 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

1015
fn bar(mut x: Pin<&mut Foo>) {
1116
foo(x);
1217
foo(x); //~ ERROR use of moved value: `x`
18+
19+
x.foo(); //~ ERROR use of moved value: `x`
20+
x.foo(); //~ ERROR use of moved value: `x`
1321
}
1422

1523
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,54 @@ 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:19:5
21+
|
22+
LL | fn bar(mut x: Pin<&mut Foo>) {
23+
| ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
24+
LL | foo(x);
25+
LL | foo(x);
26+
| - value moved here
27+
LL |
28+
LL | x.foo();
29+
| ^ value used here after move
30+
|
31+
note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary
32+
--> $DIR/feature-gate-pin_ergonomics.rs:12:11
33+
|
34+
LL | fn foo(_: Pin<&mut Foo>) {
35+
| --- ^^^^^^^^^^^^^ this parameter takes ownership of the value
36+
| |
37+
| in this function
38+
39+
error[E0382]: use of moved value: `x`
40+
--> $DIR/feature-gate-pin_ergonomics.rs:20:5
41+
|
42+
LL | fn bar(mut x: Pin<&mut Foo>) {
43+
| ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
44+
...
45+
LL | x.foo();
46+
| ----- `x` moved due to this method call
47+
LL | x.foo();
48+
| ^ value used here after move
49+
|
50+
note: `Foo::foo` takes ownership of the receiver `self`, which moves `x`
51+
--> $DIR/feature-gate-pin_ergonomics.rs:8:12
52+
|
53+
LL | fn foo(self: Pin<&mut Self>) {
54+
| ^^^^
55+
help: consider reborrowing the `Pin` instead of moving it
56+
|
57+
LL | x.as_mut().foo();
58+
| +++++++++
59+
60+
error: aborting due to 3 previous errors
2061

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

0 commit comments

Comments
 (0)