about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs49
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs10
3 files changed, 70 insertions, 5 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 0d11df11334..f955c62a443 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -239,10 +239,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
                 let region = self.next_region_var(infer::Autoref(self.span));
 
-                adjustments.push(Adjustment {
-                    kind: Adjust::ReborrowPin(region, mutbl),
-                    target,
-                });
+                target = match target.kind() {
+                    ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
+                        let inner_ty = match args[0].expect_ty().kind() {
+                            ty::Ref(_, ty, _) => *ty,
+                            _ => bug!("Expected a reference type for argument to Pin"),
+                        };
+                        Ty::new_pinned_ref(self.tcx, region, inner_ty, mutbl)
+                    }
+                    _ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"),
+                };
+
+                adjustments.push(Adjustment { kind: Adjust::ReborrowPin(region, mutbl), target });
             }
             None => {}
         }
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 43481c9704a..86584860b79 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1113,6 +1113,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                                 unstable_candidates.as_deref_mut(),
                             )
                         })
+                        .or_else(|| {
+                            self.pick_reborrow_pin_method(
+                                step,
+                                self_ty,
+                                unstable_candidates.as_deref_mut(),
+                            )
+                        })
                     })
             })
     }
@@ -1147,7 +1154,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                         })
                     }
 
-                    ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => {
+                    ty::Adt(def, args)
+                        if self.tcx.features().pin_ergonomics
+                            && self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) =>
+                    {
                         // make sure this is a pinned reference (and not a `Pin<Box>` or something)
                         if let ty::Ref(_, _, mutbl) = args[0].expect_ty().kind() {
                             pick.autoref_or_ptr_adjustment =
@@ -1186,6 +1196,43 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         })
     }
 
+    /// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`.
+    #[instrument(level = "debug", skip(self, step, unstable_candidates))]
+    fn pick_reborrow_pin_method(
+        &self,
+        step: &CandidateStep<'tcx>,
+        self_ty: Ty<'tcx>,
+        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+    ) -> Option<PickResult<'tcx>> {
+        if !self.tcx.features().pin_ergonomics {
+            return None;
+        }
+
+        // make sure self is a Pin<&mut T>
+        let inner_ty = match self_ty.kind() {
+            ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => {
+                match args[0].expect_ty().kind() {
+                    ty::Ref(_, ty, hir::Mutability::Mut) => *ty,
+                    _ => {
+                        return None;
+                    }
+                }
+            }
+            _ => return None,
+        };
+
+        let region = self.tcx.lifetimes.re_erased;
+        let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
+        self.pick_method(autopin_ty, unstable_candidates).map(|r| {
+            r.map(|mut pick| {
+                pick.autoderefs = step.autoderefs;
+                pick.autoref_or_ptr_adjustment =
+                    Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
+                pick
+            })
+        })
+    }
+
     /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
     /// special case for this is because going from `*mut T` to `*const T` with autoderefs and
     /// autorefs would require dereferencing the pointer, which is not safe.
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index db9978a7f53..fc4fb917283 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -584,6 +584,16 @@ impl<'tcx> Ty<'tcx> {
         Ty::new_ref(tcx, r, ty, hir::Mutability::Not)
     }
 
+    pub fn new_pinned_ref(
+        tcx: TyCtxt<'tcx>,
+        r: Region<'tcx>,
+        ty: Ty<'tcx>,
+        mutbl: ty::Mutability,
+    ) -> Ty<'tcx> {
+        let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None));
+        Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()]))
+    }
+
     #[inline]
     pub fn new_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mutbl: ty::Mutability) -> Ty<'tcx> {
         Ty::new(tcx, ty::RawPtr(ty, mutbl))