Allow reborrowing pinned self methods
This commit is contained in:
parent
97fbcf6773
commit
3dfb30c70a
@ -239,10 +239,18 @@ fn adjust_self_ty(
|
||||
Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
|
||||
let region = self.next_region_var(infer::Autoref(self.span));
|
||||
|
||||
adjustments.push(Adjustment {
|
||||
kind: Adjust::ReborrowPin(region, mutbl),
|
||||
target,
|
||||
});
|
||||
target = match target.kind() {
|
||||
ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
|
||||
let inner_ty = match args[0].expect_ty().kind() {
|
||||
ty::Ref(_, ty, _) => *ty,
|
||||
_ => bug!("Expected a reference type for argument to Pin"),
|
||||
};
|
||||
Ty::new_pinned_ref(self.tcx, region, inner_ty, mutbl)
|
||||
}
|
||||
_ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"),
|
||||
};
|
||||
|
||||
adjustments.push(Adjustment { kind: Adjust::ReborrowPin(region, mutbl), target });
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
@ -1113,6 +1113,13 @@ fn pick_all_method(
|
||||
unstable_candidates.as_deref_mut(),
|
||||
)
|
||||
})
|
||||
.or_else(|| {
|
||||
self.pick_reborrow_pin_method(
|
||||
step,
|
||||
self_ty,
|
||||
unstable_candidates.as_deref_mut(),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -1147,7 +1154,10 @@ fn pick_by_value_method(
|
||||
})
|
||||
}
|
||||
|
||||
ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => {
|
||||
ty::Adt(def, args)
|
||||
if self.tcx.features().pin_ergonomics
|
||||
&& 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 =
|
||||
@ -1186,6 +1196,43 @@ fn pick_autorefd_method(
|
||||
})
|
||||
}
|
||||
|
||||
/// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`.
|
||||
#[instrument(level = "debug", skip(self, step, unstable_candidates))]
|
||||
fn pick_reborrow_pin_method(
|
||||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
if !self.tcx.features().pin_ergonomics {
|
||||
return None;
|
||||
}
|
||||
|
||||
// make sure self is a Pin<&mut T>
|
||||
let inner_ty = match self_ty.kind() {
|
||||
ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => {
|
||||
match args[0].expect_ty().kind() {
|
||||
ty::Ref(_, ty, hir::Mutability::Mut) => *ty,
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let region = self.tcx.lifetimes.re_erased;
|
||||
let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
|
||||
self.pick_method(autopin_ty, unstable_candidates).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment =
|
||||
Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
|
||||
pick
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
|
||||
/// special case for this is because going from `*mut T` to `*const T` with autoderefs and
|
||||
/// autorefs would require dereferencing the pointer, which is not safe.
|
||||
|
@ -584,6 +584,16 @@ pub fn new_imm_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx>
|
||||
Ty::new_ref(tcx, r, ty, hir::Mutability::Not)
|
||||
}
|
||||
|
||||
pub fn new_pinned_ref(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
r: Region<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
mutbl: ty::Mutability,
|
||||
) -> Ty<'tcx> {
|
||||
let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None));
|
||||
Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()]))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mutbl: ty::Mutability) -> Ty<'tcx> {
|
||||
Ty::new(tcx, ty::RawPtr(ty, mutbl))
|
||||
|
@ -22,8 +22,7 @@ pub fn bar(x: Pin<&mut Foo>) {
|
||||
|
||||
Foo::baz(x);
|
||||
|
||||
// FIXME: We should allow downgrading a Pin<&mut T> to Pin<&T>
|
||||
// x.baz();
|
||||
x.baz();
|
||||
}
|
||||
|
||||
pub fn baaz(x: Pin<&Foo>) {
|
||||
|
@ -4,12 +4,20 @@
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn foo(self: Pin<&mut Self>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn foo(_: Pin<&mut Foo>) {
|
||||
}
|
||||
|
||||
fn bar(mut x: Pin<&mut Foo>) {
|
||||
foo(x);
|
||||
foo(x); //~ ERROR use of moved value: `x`
|
||||
|
||||
x.foo(); //~ ERROR use of moved value: `x`
|
||||
x.foo(); //~ ERROR use of moved value: `x`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:12:9
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:17:9
|
||||
|
|
||||
LL | fn bar(mut x: Pin<&mut Foo>) {
|
||||
| ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
|
||||
@ -9,13 +9,54 @@ LL | foo(x);
|
||||
| ^ value used here after move
|
||||
|
|
||||
note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:7:11
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:12:11
|
||||
|
|
||||
LL | fn foo(_: Pin<&mut Foo>) {
|
||||
| --- ^^^^^^^^^^^^^ this parameter takes ownership of the value
|
||||
| |
|
||||
| in this function
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:19:5
|
||||
|
|
||||
LL | fn bar(mut x: Pin<&mut Foo>) {
|
||||
| ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
|
||||
LL | foo(x);
|
||||
LL | foo(x);
|
||||
| - value moved here
|
||||
LL |
|
||||
LL | x.foo();
|
||||
| ^ value used here after move
|
||||
|
|
||||
note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:12:11
|
||||
|
|
||||
LL | fn foo(_: Pin<&mut Foo>) {
|
||||
| --- ^^^^^^^^^^^^^ this parameter takes ownership of the value
|
||||
| |
|
||||
| in this function
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:20:5
|
||||
|
|
||||
LL | fn bar(mut x: Pin<&mut Foo>) {
|
||||
| ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | x.foo();
|
||||
| ----- `x` moved due to this method call
|
||||
LL | x.foo();
|
||||
| ^ value used here after move
|
||||
|
|
||||
note: `Foo::foo` takes ownership of the receiver `self`, which moves `x`
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:8:12
|
||||
|
|
||||
LL | fn foo(self: Pin<&mut Self>) {
|
||||
| ^^^^
|
||||
help: consider reborrowing the `Pin` instead of moving it
|
||||
|
|
||||
LL | x.as_mut().foo();
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
|
Loading…
Reference in New Issue
Block a user