about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-08-09 22:59:59 +0200
committerGitHub <noreply@github.com>2023-08-09 22:59:59 +0200
commit90c0371ca931b8f109d7b28d49cfb85e146d21a7 (patch)
tree89ca7508853d08fbe46246ca1383c2bfff0974a9 /compiler
parent128cc065158d259f77479b20316a89ed2ac7a6ca (diff)
parent843549e4786a88fcd120d083bd98f8046469e054 (diff)
downloadrust-90c0371ca931b8f109d7b28d49cfb85e146d21a7.tar.gz
rust-90c0371ca931b8f109d7b28d49cfb85e146d21a7.zip
Rollup merge of #114469 - estebank:arbitrary-self-types-mut-diff, r=davidtwco
Detect method not found on arbitrary self type with different mutability

```
error[E0599]: no method named `x` found for struct `Pin<&S>` in the current scope
  --> $DIR/arbitrary_self_type_mut_difference.rs:11:18
   |
LL |     Pin::new(&S).x();
   |                  ^ help: there is a method with a similar name: `y`
   |
note: method is available for `Pin<&mut S>`
  --> $DIR/arbitrary_self_type_mut_difference.rs:6:5
   |
LL |     fn x(self: Pin<&mut Self>) {}
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
```

Related to #57994, as one of the presented cases can lead to code like this.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs79
3 files changed, 68 insertions, 17 deletions
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 2af8648455b..7cea40fdd64 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -13,7 +13,7 @@ use crate::errors::{
     YieldExprOutsideOfGenerator,
 };
 use crate::fatally_break_rust;
-use crate::method::SelfSource;
+use crate::method::{MethodCallComponents, SelfSource};
 use crate::type_error_struct;
 use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
 use crate::{
@@ -1281,7 +1281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         segment.ident,
                         SelfSource::MethodCall(rcvr),
                         error,
-                        Some((rcvr, args)),
+                        Some(MethodCallComponents { receiver: rcvr, args, full_expr: expr }),
                         expected,
                         false,
                     ) {
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 597696843c4..6dd131aa283 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -7,7 +7,7 @@ mod prelude2021;
 pub mod probe;
 mod suggest;
 
-pub use self::suggest::SelfSource;
+pub use self::suggest::{MethodCallComponents, SelfSource};
 pub use self::MethodError::*;
 
 use crate::errors::OpMethodGenericParams;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index b9d8c5a7540..2d64c5667a8 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -50,6 +50,15 @@ use rustc_hir::intravisit::Visitor;
 use std::cmp::{self, Ordering};
 use std::iter;
 
+/// After identifying that `full_expr` is a method call, we use this type to keep the expression's
+/// components readily available to us to point at the right place in diagnostics.
+#[derive(Debug, Clone, Copy)]
+pub struct MethodCallComponents<'tcx> {
+    pub receiver: &'tcx hir::Expr<'tcx>,
+    pub args: &'tcx [hir::Expr<'tcx>],
+    pub full_expr: &'tcx hir::Expr<'tcx>,
+}
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
         let tcx = self.tcx;
@@ -115,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         item_name: Ident,
         source: SelfSource<'tcx>,
         error: MethodError<'tcx>,
-        args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+        args: Option<MethodCallComponents<'tcx>>,
         expected: Expectation<'tcx>,
         trait_missing_method: bool,
     ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
@@ -257,18 +266,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn suggest_missing_writer(
         &self,
         rcvr_ty: Ty<'tcx>,
-        args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]),
+        args: MethodCallComponents<'tcx>,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
-        let mut err =
-            struct_span_err!(self.tcx.sess, args.0.span, E0599, "cannot write into `{}`", ty_str);
+        let mut err = struct_span_err!(
+            self.tcx.sess,
+            args.receiver.span,
+            E0599,
+            "cannot write into `{}`",
+            ty_str
+        );
         err.span_note(
-            args.0.span,
+            args.receiver.span,
             "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
         );
-        if let ExprKind::Lit(_) = args.0.kind {
+        if let ExprKind::Lit(_) = args.receiver.kind {
             err.span_help(
-                args.0.span.shrink_to_lo(),
+                args.receiver.span.shrink_to_lo(),
                 "a writer is needed before this format string",
             );
         };
@@ -282,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
         source: SelfSource<'tcx>,
-        args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+        args: Option<MethodCallComponents<'tcx>>,
         sugg_span: Span,
         no_match_data: &mut NoMatchData<'tcx>,
         expected: Expectation<'tcx>,
@@ -953,6 +967,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 unsatisfied_bounds = true;
             }
+        } else if let ty::Adt(def, targs) = rcvr_ty.kind() && let Some(args) = args {
+            // This is useful for methods on arbitrary self types that might have a simple
+            // mutability difference, like calling a method on `Pin<&mut Self>` that is on
+            // `Pin<&Self>`.
+            if targs.len() == 1 {
+                let mut item_segment = hir::PathSegment::invalid();
+                item_segment.ident = item_name;
+                for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] {
+                    let new_args = tcx.mk_args_from_iter(
+                        targs
+                            .iter()
+                            .map(|arg| match arg.as_type() {
+                                Some(ty) => ty::GenericArg::from(
+                                    t(tcx, tcx.lifetimes.re_erased, ty.peel_refs()),
+                                ),
+                                _ => arg,
+                            })
+                    );
+                    let rcvr_ty = Ty::new_adt(tcx, *def, new_args);
+                    if let Ok(method) = self.lookup_method_for_diagnostic(
+                        rcvr_ty,
+                        &item_segment,
+                        span,
+                        args.full_expr,
+                        args.receiver,
+                    ) {
+                        err.span_note(
+                            tcx.def_span(method.def_id),
+                            format!("{item_kind} is available for `{rcvr_ty}`"),
+                        );
+                    }
+                }
+            }
         }
 
         let label_span_not_found = |err: &mut Diagnostic| {
@@ -1111,7 +1158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 span,
                 rcvr_ty,
                 item_name,
-                args.map(|(_, args)| args.len() + 1),
+                args.map(|MethodCallComponents { args, .. }| args.len() + 1),
                 source,
                 no_match_data.out_of_scope_traits.clone(),
                 &unsatisfied_predicates,
@@ -1192,7 +1239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
-        args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+        args: Option<MethodCallComponents<'tcx>>,
         span: Span,
         err: &mut Diagnostic,
         sources: &mut Vec<CandidateSource>,
@@ -1343,7 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         rcvr_ty: Ty<'tcx>,
         source: SelfSource<'tcx>,
         item_name: Ident,
-        args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>,
+        args: Option<MethodCallComponents<'tcx>>,
         sugg_span: Span,
     ) {
         let mut has_unsuggestable_args = false;
@@ -1415,7 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 None
             };
             let mut applicability = Applicability::MachineApplicable;
-            let args = if let Some((receiver, args)) = args {
+            let args = if let Some(MethodCallComponents { receiver, args, .. }) = args {
                 // The first arg is the same kind as the receiver
                 let explicit_args = if first_arg.is_some() {
                     std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
@@ -2995,7 +3042,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
 
 fn print_disambiguation_help<'tcx>(
     item_name: Ident,
-    args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+    args: Option<MethodCallComponents<'tcx>>,
     err: &mut Diagnostic,
     trait_name: String,
     rcvr_ty: Ty<'_>,
@@ -3007,7 +3054,11 @@ fn print_disambiguation_help<'tcx>(
     fn_has_self_parameter: bool,
 ) {
     let mut applicability = Applicability::MachineApplicable;
-    let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
+    let (span, sugg) = if let (
+        ty::AssocKind::Fn,
+        Some(MethodCallComponents { receiver, args, .. }),
+    ) = (kind, args)
+    {
         let args = format!(
             "({}{})",
             rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()),