about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-09-04 00:20:39 +0200
committerGitHub <noreply@github.com>2022-09-04 00:20:39 +0200
commitbd9750fd2ad7edee3c4cb28b42596ceacb5813a3 (patch)
treedd0e688052f26a188c5f08c20b1dfb181fc367bf
parent84f0c3f79a85329dd79a54694ff8a7f427c842e9 (diff)
parent12a49523697f4a64609558b467c460b9a4b333c1 (diff)
downloadrust-bd9750fd2ad7edee3c4cb28b42596ceacb5813a3.tar.gz
rust-bd9750fd2ad7edee3c4cb28b42596ceacb5813a3.zip
Rollup merge of #100302 - compiler-errors:deref-path-methods, r=jackh726
Suggest associated method on deref types when path syntax method fails

Fixes #100278
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs62
-rw-r--r--src/test/ui/suggestions/deref-path-method.rs6
-rw-r--r--src/test/ui/suggestions/deref-path-method.stderr14
3 files changed, 80 insertions, 2 deletions
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index e99782fdc65..998405bcbe1 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -16,8 +16,8 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
 use rustc_middle::traits::util::supertraits;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::ToPolyTraitRef;
 use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Symbol;
 use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
@@ -30,7 +30,7 @@ use rustc_trait_selection::traits::{
 use std::cmp::Ordering;
 use std::iter;
 
-use super::probe::{Mode, ProbeScope};
+use super::probe::{IsSuggestion, Mode, ProbeScope};
 use super::{CandidateSource, MethodError, NoMatchData};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -1069,6 +1069,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
 
+                self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
+
                 return Some(err);
             }
 
@@ -1651,6 +1653,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    fn check_for_deref_method(
+        &self,
+        err: &mut Diagnostic,
+        self_source: SelfSource<'tcx>,
+        rcvr_ty: Ty<'tcx>,
+        item_name: Ident,
+    ) {
+        let SelfSource::QPath(ty) = self_source else { return; };
+        for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) {
+            if let Ok(pick) = self.probe_for_name(
+                ty.span,
+                Mode::Path,
+                item_name,
+                IsSuggestion(true),
+                deref_ty,
+                ty.hir_id,
+                ProbeScope::TraitsInScope,
+            ) {
+                if deref_ty.is_suggestable(self.tcx, true)
+                    // If this method receives `&self`, then the provided
+                    // argument _should_ coerce, so it's valid to suggest
+                    // just changing the path.
+                    && pick.item.fn_has_self_parameter
+                    && let Some(self_ty) =
+                        self.tcx.fn_sig(pick.item.def_id).inputs().skip_binder().get(0)
+                    && self_ty.is_ref()
+                {
+                    let suggested_path = match deref_ty.kind() {
+                        ty::Bool
+                        | ty::Char
+                        | ty::Int(_)
+                        | ty::Uint(_)
+                        | ty::Float(_)
+                        | ty::Adt(_, _)
+                        | ty::Str
+                        | ty::Projection(_)
+                        | ty::Param(_) => format!("{deref_ty}"),
+                        _ => format!("<{deref_ty}>"),
+                    };
+                    err.span_suggestion_verbose(
+                        ty.span,
+                        format!("the function `{item_name}` is implemented on `{deref_ty}`"),
+                        suggested_path,
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    err.span_note(
+                        ty.span,
+                        format!("the function `{item_name}` is implemented on `{deref_ty}`"),
+                    );
+                }
+                return;
+            }
+        }
+    }
+
     /// Print out the type for use in value namespace.
     fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
         match ty.kind() {
diff --git a/src/test/ui/suggestions/deref-path-method.rs b/src/test/ui/suggestions/deref-path-method.rs
new file mode 100644
index 00000000000..0281cdb6b37
--- /dev/null
+++ b/src/test/ui/suggestions/deref-path-method.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let vec = Vec::new();
+    Vec::contains(&vec, &0);
+    //~^ ERROR no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope
+    //~| HELP the function `contains` is implemented on `[_]`
+}
diff --git a/src/test/ui/suggestions/deref-path-method.stderr b/src/test/ui/suggestions/deref-path-method.stderr
new file mode 100644
index 00000000000..1cc37d61151
--- /dev/null
+++ b/src/test/ui/suggestions/deref-path-method.stderr
@@ -0,0 +1,14 @@
+error[E0599]: no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope
+  --> $DIR/deref-path-method.rs:3:10
+   |
+LL |     Vec::contains(&vec, &0);
+   |          ^^^^^^^^ function or associated item not found in `Vec<_, _>`
+   |
+help: the function `contains` is implemented on `[_]`
+   |
+LL |     <[_]>::contains(&vec, &0);
+   |     ~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.