Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Begin experimental support for pin reborrowing #130526

Merged
merged 5 commits into from
Sep 20, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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.
eholk committed Sep 19, 2024
commit b2b76fb70659f55d5e1842b28c7d6c451ae916d9
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
@@ -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;
5 changes: 1 addition & 4 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
@@ -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,
}]
})
12 changes: 5 additions & 7 deletions compiler/rustc_hir_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
@@ -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))
5 changes: 2 additions & 3 deletions compiler/rustc_middle/src/ty/adjustment.rs
Original file line number Diff line number Diff line change
@@ -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)`
100 changes: 57 additions & 43 deletions compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
@@ -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));
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),
};
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 {
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")
}
}
// 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 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"),
};

// 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 @@ 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");
};
1 change: 0 additions & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -1418,7 +1418,6 @@ symbols! {
pic,
pie,
pin,
pin_as_mut,
pin_ergonomics,
platform_intrinsics,
plugin,
1 change: 0 additions & 1 deletion library/core/src/pin.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions tests/ui/async-await/pin-reborrow-shorter.rs
Original file line number Diff line number Diff line change
@@ -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() {}