From 5497317aa542c490b1540edf5907dd29739bcecb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Nov 2022 19:18:38 +0000 Subject: [PATCH] Do autoderef to match impl against rcvr --- .../rustc_hir_typeck/src/method/suggest.rs | 92 +++++++++---------- .../suggest-assoc-fn-call-deref.fixed | 15 +++ .../suggest-assoc-fn-call-deref.rs | 15 +++ .../suggest-assoc-fn-call-deref.stderr | 19 ++++ 4 files changed, 95 insertions(+), 46 deletions(-) create mode 100644 src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed create mode 100644 src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs create mode 100644 src/test/ui/suggestions/suggest-assoc-fn-call-deref.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 821492179136..edfe12963dc6 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> = 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::>(); + 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 000000000000..8d96cf590c39 --- /dev/null +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed @@ -0,0 +1,15 @@ +// run-rustfix + +#![allow(unused)] + +struct Foo(T); + +impl Foo { + fn test() -> i32 { 1 } +} + +fn main() { + let x = Box::new(Foo(1i32)); + Foo::::test(); + //~^ ERROR no method named `test` found for struct `Box>` 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 000000000000..186901f75a84 --- /dev/null +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs @@ -0,0 +1,15 @@ +// run-rustfix + +#![allow(unused)] + +struct Foo(T); + +impl Foo { + fn test() -> i32 { 1 } +} + +fn main() { + let x = Box::new(Foo(1i32)); + x.test(); + //~^ ERROR no method named `test` found for struct `Box>` 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 000000000000..00fb96f03266 --- /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>` 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::::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` + --> $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`.