Rollup merge of #130526 - eholk:pin-reborrow, r=compiler-errors
Begin experimental support for pin reborrowing This commit adds basic support for reborrowing `Pin` types in argument position. At the moment it only supports reborrowing `Pin<&mut T>` as `Pin<&mut T>` by inserting a call to `Pin::as_mut()`, and only in argument position (not as the receiver in a method call). This PR makes the following example compile: ```rust #![feature(pin_ergonomics)] fn foo(_: Pin<&mut Foo>) { } fn bar(mut x: Pin<&mut Foo>) { foo(x); foo(x); } ``` Previously, you would have had to write `bar` as: ```rust fn bar(mut x: Pin<&mut Foo>) { foo(x.as_mut()); foo(x); } ``` Tracking: - #130494 r? `@compiler-errors`
This commit is contained in:
commit
fe5f734e6a
17 changed files with 316 additions and 3 deletions
|
@ -74,6 +74,7 @@ impl<'tcx> Cx<'tcx> {
|
|||
self.thir.exprs.push(expr)
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, expr, span))]
|
||||
fn apply_adjustment(
|
||||
&mut self,
|
||||
hir_expr: &'tcx hir::Expr<'tcx>,
|
||||
|
@ -146,6 +147,67 @@ 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(region, mutbl) => {
|
||||
debug!("apply ReborrowPin adjustment");
|
||||
// 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 borrow_kind = match mutbl {
|
||||
hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
|
||||
hir::Mutability::Not => BorrowKind::Shared,
|
||||
};
|
||||
let new_pin_target = Ty::new_ref(self.tcx, region, ptr_target_ty, mutbl);
|
||||
let expr = self.thir.exprs.push(Expr {
|
||||
temp_lifetime,
|
||||
ty: new_pin_target,
|
||||
span,
|
||||
kind: ExprKind::Borrow { borrow_kind, arg },
|
||||
});
|
||||
|
||||
// kind = Pin { __pointer: pointer }
|
||||
let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(span));
|
||||
let args = self.tcx.mk_args(&[new_pin_target.into()]);
|
||||
let kind = ExprKind::Adt(Box::new(AdtExpr {
|
||||
adt_def: self.tcx.adt_def(pin_did),
|
||||
variant_index: FIRST_VARIANT,
|
||||
args,
|
||||
fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
|
||||
user_ty: None,
|
||||
base: None,
|
||||
}));
|
||||
|
||||
debug!(?kind);
|
||||
kind
|
||||
}
|
||||
};
|
||||
|
||||
Expr { temp_lifetime, ty: adjustment.target, span, kind }
|
||||
|
@ -1014,7 +1076,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");
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue