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
@ -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;
|
||||
|
@ -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,
|
||||
}]
|
||||
})
|
||||
|
@ -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))
|
||||
|
@ -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 @@ 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");
|
||||
};
|
||||
|
@ -1418,7 +1418,6 @@
|
||||
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…
Reference in New Issue
Block a user