about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs24
-rw-r--r--tests/ui/self/arbitrary_self_types_needing_mut_pin.fixed3
-rw-r--r--tests/ui/self/arbitrary_self_types_needing_mut_pin.stderr10
3 files changed, 25 insertions, 12 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 3ea2d310b0f..770adb6fc7d 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -2496,13 +2496,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // FIXME: probe for all types that *could* be arbitrary self-types, not
             // just this list.
             for (rcvr_ty, post, pin_call) in &[
-                (rcvr_ty, "", ""),
+                (rcvr_ty, "", None),
                 (
                     Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
                     "&mut ",
-                    "as_mut",
+                    Some("as_mut"),
+                ),
+                (
+                    Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
+                    "&",
+                    Some("as_ref"),
                 ),
-                (Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&", "as_ref"),
             ] {
                 match self.lookup_probe_for_diagnostic(
                     item_name,
@@ -2594,13 +2598,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                     }
                 }
-                // We special case the situation where `Pin::new` wouldn't work, and isntead
+                // We special case the situation where `Pin::new` wouldn't work, and instead
                 // suggest using the `pin!()` macro instead.
                 if let Some(new_rcvr_t) = Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin)
+                    // We didn't find an alternative receiver for the method.
                     && !alt_rcvr_sugg
+                    // `T: !Unpin`
                     && !unpin
+                    // The method isn't `as_ref`, as it would provide a wrong suggestion for `Pin`.
                     && sym::as_ref != item_name.name
-                    && *pin_call != ""
+                    // Either `Pin::as_ref` or `Pin::as_mut`.
+                    && let Some(pin_call) = pin_call
+                    // Search for `item_name` as a method accessible on `Pin<T>`.
                     && let Ok(pick) = self.lookup_probe_for_diagnostic(
                         item_name,
                         new_rcvr_t,
@@ -2608,8 +2617,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ProbeScope::AllTraits,
                         return_type,
                     )
+                    // We skip some common traits that we don't want to consider because autoderefs
+                    // would take care of them.
                     && !skippable.contains(&Some(pick.item.container_id(self.tcx)))
+                    // We don't want to go through derefs.
                     && pick.autoderefs == 0
+                    // Check that the method of the same name that was found on the new `Pin<T>`
+                    // receiver has the same number of arguments that appear in the user's code.
                     && inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
                 {
                     let indent = self.tcx.sess
diff --git a/tests/ui/self/arbitrary_self_types_needing_mut_pin.fixed b/tests/ui/self/arbitrary_self_types_needing_mut_pin.fixed
index ccd65ff4091..a400a1672a4 100644
--- a/tests/ui/self/arbitrary_self_types_needing_mut_pin.fixed
+++ b/tests/ui/self/arbitrary_self_types_needing_mut_pin.fixed
@@ -8,5 +8,6 @@ impl S {
 }
 
 fn main() {
-    Pin::new(&mut S).x(); //~ ERROR no method named `x` found
+    let mut pinned = std::pin::pin!(S);
+    pinned.as_mut().x(); //~ ERROR no method named `x` found
 }
diff --git a/tests/ui/self/arbitrary_self_types_needing_mut_pin.stderr b/tests/ui/self/arbitrary_self_types_needing_mut_pin.stderr
index f34ce4dce49..5dcb5861120 100644
--- a/tests/ui/self/arbitrary_self_types_needing_mut_pin.stderr
+++ b/tests/ui/self/arbitrary_self_types_needing_mut_pin.stderr
@@ -4,16 +4,14 @@ error[E0599]: no method named `x` found for struct `S` in the current scope
 LL | struct S;
    | -------- method `x` not found for this struct
 ...
-LL |     fn x(self: Pin<&mut Self>) {
-   |        - the method is available for `Pin<&mut S>` here
-...
 LL |     S.x();
    |       ^ method not found in `S`
    |
-help: consider wrapping the receiver expression with the appropriate type
+help: consider pinning the expression
+   |
+LL ~     let mut pinned = std::pin::pin!(S);
+LL ~     pinned.as_mut().x();
    |
-LL |     Pin::new(&mut S).x();
-   |     +++++++++++++  +
 
 error: aborting due to previous error