about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Holk <ericholk@microsoft.com>2024-09-19 17:23:46 -0700
committerEric Holk <ericholk@microsoft.com>2024-09-23 09:12:36 -0700
commit97fbcf6773fa2d00675cbd7ea8dcdac1d6772072 (patch)
treedd78c090c8e789eb8e7e7c49c9aee0da94bd2cda
parentc22a4215a0f6fb676d3774d3763d9da1462414f5 (diff)
downloadrust-97fbcf6773fa2d00675cbd7ea8dcdac1d6772072.tar.gz
rust-97fbcf6773fa2d00675cbd7ea8dcdac1d6772072.zip
Allow reborrowing Pin<&mut Self>
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs32
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs32
-rw-r--r--tests/ui/async-await/pin-reborrow-self.rs20
4 files changed, 74 insertions, 19 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index e3b0fa78eb7..0d11df11334 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -235,6 +235,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                     target,
                 });
             }
+
+            Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
+                let region = self.next_region_var(infer::Autoref(self.span));
+
+                adjustments.push(Adjustment {
+                    kind: Adjust::ReborrowPin(region, mutbl),
+                    target,
+                });
+            }
             None => {}
         }
 
diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
index a8b5b6165db..b20592c85d2 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
@@ -121,16 +121,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             mutbl.ref_prefix_str()
                         }
                         Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
+                        Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
+                            hir::Mutability::Mut => "Pin<&mut ",
+                            hir::Mutability::Not => "Pin<&",
+                        },
                     };
                     if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
                     {
-                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                        let mut self_adjusted =
+                            if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                                pick.autoref_or_ptr_adjustment
+                            {
+                                format!("{derefs}{self_expr} as *const _")
+                            } else {
+                                format!("{autoref}{derefs}{self_expr}")
+                            };
+
+                        if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) =
                             pick.autoref_or_ptr_adjustment
                         {
-                            format!("{derefs}{self_expr} as *const _")
-                        } else {
-                            format!("{autoref}{derefs}{self_expr}")
-                        };
+                            self_adjusted.push('>');
+                        }
 
                         lint.span_suggestion(
                             sp,
@@ -400,6 +411,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let autoref = match pick.autoref_or_ptr_adjustment {
             Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(),
             Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
+            Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
+                hir::Mutability::Mut => "Pin<&mut ",
+                hir::Mutability::Not => "Pin<&",
+            },
         };
 
         let (expr_text, precise) = if let Some(expr_text) = expr
@@ -412,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ("(..)".to_string(), false)
         };
 
-        let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+        let mut adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
             pick.autoref_or_ptr_adjustment
         {
             format!("{derefs}{expr_text} as *const _")
@@ -420,6 +435,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             format!("{autoref}{derefs}{expr_text}")
         };
 
+        if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = pick.autoref_or_ptr_adjustment
+        {
+            adjusted_text.push('>');
+        }
+
         (adjusted_text, precise)
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 3828b40b885..43481c9704a 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -136,7 +136,7 @@ enum ProbeResult {
 /// `mut`), or it has type `*mut T` and we convert it to `*const T`.
 #[derive(Debug, PartialEq, Copy, Clone)]
 pub(crate) enum AutorefOrPtrAdjustment {
-    /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
+    /// Receiver has type `T`, add `&` or `&mut` (if `T` is `mut`), and maybe also "unsize" it.
     /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
     Autoref {
         mutbl: hir::Mutability,
@@ -147,6 +147,9 @@ pub(crate) enum AutorefOrPtrAdjustment {
     },
     /// Receiver has type `*mut T`, convert to `*const T`
     ToConstPtr,
+
+    /// Reborrow a `Pin<&mut T>` or `Pin<&T>`.
+    ReborrowPin(hir::Mutability),
 }
 
 impl AutorefOrPtrAdjustment {
@@ -154,6 +157,7 @@ impl AutorefOrPtrAdjustment {
         match self {
             AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
             AutorefOrPtrAdjustment::ToConstPtr => false,
+            AutorefOrPtrAdjustment::ReborrowPin(_) => false,
         }
     }
 }
@@ -1133,13 +1137,25 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
 
-                // Insert a `&*` or `&mut *` if this is a reference type:
-                if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() {
-                    pick.autoderefs += 1;
-                    pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
-                        mutbl,
-                        unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
-                    })
+                match *step.self_ty.value.value.kind() {
+                    // Insert a `&*` or `&mut *` if this is a reference type:
+                    ty::Ref(_, _, mutbl) => {
+                        pick.autoderefs += 1;
+                        pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
+                            mutbl,
+                            unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
+                        })
+                    }
+
+                    ty::Adt(def, args) if 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 =
+                                Some(AutorefOrPtrAdjustment::ReborrowPin(*mutbl));
+                        }
+                    }
+
+                    _ => (),
                 }
 
                 pick
diff --git a/tests/ui/async-await/pin-reborrow-self.rs b/tests/ui/async-await/pin-reborrow-self.rs
index b60b6982bb8..ab36ce575e1 100644
--- a/tests/ui/async-await/pin-reborrow-self.rs
+++ b/tests/ui/async-await/pin-reborrow-self.rs
@@ -1,24 +1,34 @@
 //@ check-pass
-//@ignore-test
-
-// Currently ignored due to self reborrowing not being implemented for Pin
 
 #![feature(pin_ergonomics)]
 #![allow(incomplete_features)]
 
 use std::pin::Pin;
 
-struct Foo;
+pub struct Foo;
 
 impl Foo {
     fn foo(self: Pin<&mut Self>) {
     }
+
+    fn baz(self: Pin<&Self>) {
+    }
 }
 
-fn bar(x: Pin<&mut Foo>) {
+pub fn bar(x: Pin<&mut Foo>) {
     x.foo();
     x.foo(); // for this to work we need to automatically reborrow,
              // as if the user had written `x.as_mut().foo()`.
+
+    Foo::baz(x);
+
+    // FIXME: We should allow downgrading a Pin<&mut T> to Pin<&T>
+    // x.baz();
+}
+
+pub fn baaz(x: Pin<&Foo>) {
+    x.baz();
+    x.baz();
 }
 
 fn main() {}