Allow shortening reborrows
Generating a call to `as_mut()` let to more restrictive borrows than what reborrowing usually gives us. Instead, we change the desugaring to reborrow the pin internals directly which makes things more expressive.
This commit is contained in:
parent
a73c8b1171
commit
b2b76fb706
8 changed files with 77 additions and 58 deletions
|
@ -395,7 +395,6 @@ language_item_table! {
|
|||
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None;
|
||||
|
||||
PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None;
|
||||
PinAsMut, sym::pin_as_mut, as_mut_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None;
|
||||
|
||||
RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct, GenericRequirement::None;
|
||||
RangeFull, sym::RangeFull, range_full_struct, Target::Struct, GenericRequirement::None;
|
||||
|
|
|
@ -824,10 +824,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// add the adjustments.
|
||||
self.unify_and(a, b, |_inner_ty| {
|
||||
vec![Adjustment {
|
||||
kind: Adjust::ReborrowPin(AutoBorrow::Ref(
|
||||
b_region,
|
||||
AutoBorrowMutability::Mut { allow_two_phase_borrow: AllowTwoPhase::No },
|
||||
)),
|
||||
kind: Adjust::ReborrowPin(b_region, hir::Mutability::Mut),
|
||||
target: b,
|
||||
}]
|
||||
})
|
||||
|
|
|
@ -781,14 +781,12 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
self.walk_autoref(expr, &place_with_id, autoref);
|
||||
}
|
||||
|
||||
adjustment::Adjust::ReborrowPin(ref autoref) => {
|
||||
adjustment::Adjust::ReborrowPin(_, mutbl) => {
|
||||
// Reborrowing a Pin is like a combinations of a deref and a borrow, so we do
|
||||
// both.
|
||||
let bk = match autoref {
|
||||
adjustment::AutoBorrow::Ref(_, m) => {
|
||||
ty::BorrowKind::from_mutbl((*m).into())
|
||||
}
|
||||
adjustment::AutoBorrow::RawPtr(m) => ty::BorrowKind::from_mutbl(*m),
|
||||
let bk = match mutbl {
|
||||
ty::Mutability::Not => ty::BorrowKind::ImmBorrow,
|
||||
ty::Mutability::Mut => ty::BorrowKind::MutBorrow,
|
||||
};
|
||||
self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
|
||||
}
|
||||
|
@ -1296,7 +1294,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
adjustment::Adjust::NeverToAny
|
||||
| adjustment::Adjust::Pointer(_)
|
||||
| adjustment::Adjust::Borrow(_)
|
||||
| adjustment::Adjust::ReborrowPin(_)
|
||||
| adjustment::Adjust::ReborrowPin(..)
|
||||
| adjustment::Adjust::DynStar => {
|
||||
// Result is an rvalue.
|
||||
Ok(self.cat_rvalue(expr.hir_id, target))
|
||||
|
|
|
@ -105,9 +105,8 @@ pub enum Adjust<'tcx> {
|
|||
/// Cast into a dyn* object.
|
||||
DynStar,
|
||||
|
||||
/// Take a `Pin<Ptr>` and call either `as_mut()` or `as_ref()` to get a `Pin<&mut T>` or
|
||||
/// `Pin<&T>`.
|
||||
ReborrowPin(AutoBorrow<'tcx>),
|
||||
/// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`.
|
||||
ReborrowPin(ty::Region<'tcx>, hir::Mutability),
|
||||
}
|
||||
|
||||
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
|
||||
|
|
|
@ -147,50 +147,64 @@ impl<'tcx> Cx<'tcx> {
|
|||
ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) }
|
||||
}
|
||||
Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) },
|
||||
Adjust::ReborrowPin(AutoBorrow::Ref(region, m)) => {
|
||||
Adjust::ReborrowPin(region, mutbl) => {
|
||||
debug!("apply ReborrowPin adjustment");
|
||||
match m {
|
||||
AutoBorrowMutability::Mut { .. } => {
|
||||
// Rewrite `$expr` as `Pin::as_mut(&mut $expr)`
|
||||
let as_mut_method =
|
||||
self.tcx().require_lang_item(rustc_hir::LangItem::PinAsMut, Some(span));
|
||||
// Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }`
|
||||
|
||||
// We'll need these types later on
|
||||
let pin_ty_args = match expr.ty.kind() {
|
||||
ty::Adt(_, args) => args,
|
||||
_ => bug!("ReborrowPin with non-Pin type"),
|
||||
};
|
||||
let as_mut_ty =
|
||||
Ty::new_fn_def(self.tcx, as_mut_method, pin_ty_args.into_iter());
|
||||
|
||||
let ty = Ty::new_ref(self.tcx, region, expr.ty, ty::Mutability::Mut);
|
||||
let arg = ExprKind::Borrow {
|
||||
borrow_kind: BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
|
||||
arg: self.thir.exprs.push(expr),
|
||||
let pin_ty = pin_ty_args.iter().next().unwrap().expect_ty();
|
||||
let ptr_target_ty = match pin_ty.kind() {
|
||||
ty::Ref(_, ty, _) => *ty,
|
||||
_ => bug!("ReborrowPin with non-Ref type"),
|
||||
};
|
||||
debug!(?arg, "borrow arg");
|
||||
let arg = self.thir.exprs.push(Expr { temp_lifetime, ty, span, kind: arg });
|
||||
|
||||
let kind = ExprKind::Call {
|
||||
ty: as_mut_ty,
|
||||
fun: self.thir.exprs.push(Expr {
|
||||
// pointer = ($expr).__pointer
|
||||
let pointer_target = ExprKind::Field {
|
||||
lhs: self.thir.exprs.push(expr),
|
||||
variant_index: FIRST_VARIANT,
|
||||
name: FieldIdx::from(0u32),
|
||||
};
|
||||
let arg = Expr { temp_lifetime, ty: pin_ty, span, kind: pointer_target };
|
||||
let arg = self.thir.exprs.push(arg);
|
||||
|
||||
// arg = *pointer
|
||||
let expr = ExprKind::Deref { arg };
|
||||
let arg = self.thir.exprs.push(Expr {
|
||||
temp_lifetime,
|
||||
ty: as_mut_ty,
|
||||
ty: ptr_target_ty,
|
||||
span,
|
||||
kind: ExprKind::ZstLiteral { user_ty: None },
|
||||
}),
|
||||
args: Box::new([arg]),
|
||||
from_hir_call: true,
|
||||
fn_span: span,
|
||||
};
|
||||
kind: expr,
|
||||
});
|
||||
|
||||
// expr = &mut target
|
||||
let expr = self.thir.exprs.push(Expr {
|
||||
temp_lifetime,
|
||||
ty: Ty::new_ref(self.tcx, region, ptr_target_ty, mutbl),
|
||||
span,
|
||||
kind: ExprKind::Borrow {
|
||||
borrow_kind: BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
|
||||
arg,
|
||||
},
|
||||
});
|
||||
|
||||
// kind = Pin { __pointer: pointer }
|
||||
let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(span));
|
||||
let kind = ExprKind::Adt(Box::new(AdtExpr {
|
||||
adt_def: self.tcx.adt_def(pin_did),
|
||||
variant_index: FIRST_VARIANT,
|
||||
args: pin_ty_args,
|
||||
fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
|
||||
user_ty: None,
|
||||
base: None,
|
||||
}));
|
||||
|
||||
debug!(?kind);
|
||||
kind
|
||||
}
|
||||
AutoBorrowMutability::Not => {
|
||||
// FIXME: We need to call Pin::as_ref on the expression
|
||||
bug!("ReborrowPin with shared reference is not implemented yet")
|
||||
}
|
||||
}
|
||||
}
|
||||
Adjust::ReborrowPin(AutoBorrow::RawPtr(_)) => bug!("ReborrowPin with raw pointer"),
|
||||
};
|
||||
|
||||
Expr { temp_lifetime, ty: adjustment.target, span, kind }
|
||||
|
@ -1059,7 +1073,7 @@ impl<'tcx> Cx<'tcx> {
|
|||
|
||||
// Reconstruct the output assuming it's a reference with the
|
||||
// same region and mutability as the receiver. This holds for
|
||||
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
|
||||
// `Deref(Mut)::deref(_mut)` and `Index(Mut)::index(_mut)`.
|
||||
let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else {
|
||||
span_bug!(span, "overloaded_place: receiver is not a reference");
|
||||
};
|
||||
|
|
|
@ -1418,7 +1418,6 @@ symbols! {
|
|||
pic,
|
||||
pie,
|
||||
pin,
|
||||
pin_as_mut,
|
||||
pin_ergonomics,
|
||||
platform_intrinsics,
|
||||
plugin,
|
||||
|
|
|
@ -1408,7 +1408,6 @@ impl<Ptr: DerefMut> Pin<Ptr> {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(not(bootstrap), lang = "pin_as_mut")]
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
#[inline(always)]
|
||||
pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> {
|
||||
|
|
14
tests/ui/async-await/pin-reborrow-shorter.rs
Normal file
14
tests/ui/async-await/pin-reborrow-shorter.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
//@check-pass
|
||||
|
||||
#![feature(pin_ergonomics)]
|
||||
#![allow(dead_code, incomplete_features)]
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
fn shorter<'b, T: 'b>(_: Pin<&'b mut T>) {}
|
||||
|
||||
fn test<'a: 'b, 'b, T: 'a>(x: Pin<&'a mut T>) {
|
||||
shorter::<'b>(x);
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue