about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-11-14 19:18:38 +0000
committerMichael Goulet <michael@errs.io>2022-11-14 19:29:37 +0000
commit5497317aa542c490b1540edf5907dd29739bcecb (patch)
tree18429f0dc57acd2caa1693ef91872e8329548031
parentbf607dae3f555f714c814a03478be560ae1c37e8 (diff)
downloadrust-5497317aa542c490b1540edf5907dd29739bcecb.tar.gz
rust-5497317aa542c490b1540edf5907dd29739bcecb.zip
Do autoderef to match impl against rcvr
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs92
-rw-r--r--src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed15
-rw-r--r--src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs15
-rw-r--r--src/test/ui/suggestions/suggest-assoc-fn-call-deref.stderr19
4 files changed, 95 insertions, 46 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 82149217913..edfe12963dc 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -20,11 +20,10 @@ use rustc_infer::infer::{
 };
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::traits::util::supertraits;
+use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::{
-    self, DefIdTree, GenericArg, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable,
-};
+use rustc_middle::ty::{self, DefIdTree, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable};
 use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Symbol;
@@ -1090,50 +1089,51 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // When the "method" is resolved through dereferencing, we really want the
             // original type that has the associated function for accurate suggestions.
             // (#61411)
-            let ty = self.tcx.type_of(*impl_did);
-            match (&ty.peel_refs().kind(), &rcvr_ty.peel_refs().kind()) {
-                (ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => {
-                    // If there are any inferred arguments, (`{integer}`), we should replace
-                    // them with underscores to allow the compiler to infer them
-                    let infer_substs: Vec<GenericArg<'_>> = substs
-                        .into_iter()
-                        .map(|arg| {
-                            if !arg.is_suggestable(self.tcx, true) {
-                                has_unsuggestable_args = true;
-                                match arg.unpack() {
-                                    GenericArgKind::Lifetime(_) => self
-                                        .next_region_var(RegionVariableOrigin::MiscVariable(
-                                            rustc_span::DUMMY_SP,
-                                        ))
-                                        .into(),
-                                    GenericArgKind::Type(_) => self
-                                        .next_ty_var(TypeVariableOrigin {
-                                            span: rustc_span::DUMMY_SP,
-                                            kind: TypeVariableOriginKind::MiscVariable,
-                                        })
-                                        .into(),
-                                    GenericArgKind::Const(arg) => self
-                                        .next_const_var(
-                                            arg.ty(),
-                                            ConstVariableOrigin {
-                                                span: rustc_span::DUMMY_SP,
-                                                kind: ConstVariableOriginKind::MiscVariable,
-                                            },
-                                        )
-                                        .into(),
-                                }
-                            } else {
-                                arg
-                            }
-                        })
-                        .collect::<Vec<_>>();
+            let impl_ty = self.tcx.type_of(*impl_did);
+            let target_ty = self
+                .autoderef(sugg_span, rcvr_ty)
+                .find(|(rcvr_ty, _)| {
+                    DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }
+                        .types_may_unify(*rcvr_ty, impl_ty)
+                })
+                .map_or(impl_ty, |(ty, _)| ty)
+                .peel_refs();
+            if let ty::Adt(def, substs) = target_ty.kind() {
+                // If there are any inferred arguments, (`{integer}`), we should replace
+                // them with underscores to allow the compiler to infer them
+                let infer_substs = self.tcx.mk_substs(substs.into_iter().map(|arg| {
+                    if !arg.is_suggestable(self.tcx, true) {
+                        has_unsuggestable_args = true;
+                        match arg.unpack() {
+                            GenericArgKind::Lifetime(_) => self
+                                .next_region_var(RegionVariableOrigin::MiscVariable(
+                                    rustc_span::DUMMY_SP,
+                                ))
+                                .into(),
+                            GenericArgKind::Type(_) => self
+                                .next_ty_var(TypeVariableOrigin {
+                                    span: rustc_span::DUMMY_SP,
+                                    kind: TypeVariableOriginKind::MiscVariable,
+                                })
+                                .into(),
+                            GenericArgKind::Const(arg) => self
+                                .next_const_var(
+                                    arg.ty(),
+                                    ConstVariableOrigin {
+                                        span: rustc_span::DUMMY_SP,
+                                        kind: ConstVariableOriginKind::MiscVariable,
+                                    },
+                                )
+                                .into(),
+                        }
+                    } else {
+                        arg
+                    }
+                }));
 
-                    self.tcx.value_path_str_with_substs(
-                        def_actual.did(),
-                        self.tcx.intern_substs(&infer_substs),
-                    )
-                }
-                _ => self.ty_to_value_string(ty.peel_refs()),
+                self.tcx.value_path_str_with_substs(def.did(), infer_substs)
+            } else {
+                self.ty_to_value_string(target_ty)
             }
         } else {
             self.ty_to_value_string(rcvr_ty.peel_refs())
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed
new file mode 100644
index 00000000000..8d96cf590c3
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo<T>(T);
+
+impl<T> Foo<T> {
+    fn test() -> i32 { 1 }
+}
+
+fn main() {
+    let x = Box::new(Foo(1i32));
+    Foo::<i32>::test();
+    //~^ ERROR no method named `test` found for struct `Box<Foo<i32>>` in the current scope
+}
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs
new file mode 100644
index 00000000000..186901f75a8
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo<T>(T);
+
+impl<T> Foo<T> {
+    fn test() -> i32 { 1 }
+}
+
+fn main() {
+    let x = Box::new(Foo(1i32));
+    x.test();
+    //~^ ERROR no method named `test` found for struct `Box<Foo<i32>>` in the current scope
+}
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-deref.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.stderr
new file mode 100644
index 00000000000..00fb96f0326
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.stderr
@@ -0,0 +1,19 @@
+error[E0599]: no method named `test` found for struct `Box<Foo<i32>>` in the current scope
+  --> $DIR/suggest-assoc-fn-call-deref.rs:13:7
+   |
+LL |     x.test();
+   |     --^^^^--
+   |     | |
+   |     | this is an associated function, not a method
+   |     help: use associated function syntax instead: `Foo::<i32>::test()`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in an impl for the type `Foo<T>`
+  --> $DIR/suggest-assoc-fn-call-deref.rs:8:5
+   |
+LL |     fn test() -> i32 { 1 }
+   |     ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.