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:
Eric Holk 2024-09-19 11:18:00 -07:00
parent a73c8b1171
commit b2b76fb706
No known key found for this signature in database
GPG Key ID: F1A772BB658A63E1
8 changed files with 77 additions and 58 deletions

View File

@ -395,7 +395,6 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
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;

View File

@ -824,10 +824,7 @@ fn coerce_pin(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'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,
}]
})

View File

@ -781,14 +781,12 @@ fn walk_adjustment(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
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 @@ fn cat_expr_adjusted_with<F>(
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))

View File

@ -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)`

View File

@ -147,50 +147,64 @@ fn apply_adjustment(
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));
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());
// Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }`
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),
};
debug!(?arg, "borrow arg");
let arg = self.thir.exprs.push(Expr { temp_lifetime, ty, span, kind: arg });
// 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 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"),
};
let kind = ExprKind::Call {
ty: as_mut_ty,
fun: self.thir.exprs.push(Expr {
temp_lifetime,
ty: as_mut_ty,
span,
kind: ExprKind::ZstLiteral { user_ty: None },
}),
args: Box::new([arg]),
from_hir_call: true,
fn_span: span,
};
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")
}
}
// 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: ptr_target_ty,
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
}
Adjust::ReborrowPin(AutoBorrow::RawPtr(_)) => bug!("ReborrowPin with raw pointer"),
};
Expr { temp_lifetime, ty: adjustment.target, span, kind }
@ -1059,7 +1073,7 @@ fn overloaded_place(
// 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");
};

View File

@ -1418,7 +1418,6 @@
pic,
pie,
pin,
pin_as_mut,
pin_ergonomics,
platform_intrinsics,
plugin,

View File

@ -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> {

View 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() {}