Do autoderef to match impl against rcvr

This commit is contained in:
Michael Goulet 2022-11-14 19:18:38 +00:00
parent bf607dae3f
commit 5497317aa5
4 changed files with 95 additions and 46 deletions

View File

@ -20,11 +20,10 @@
};
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,14 +1089,19 @@ fn suggest_associated_call_syntax(
// 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 => {
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: Vec<GenericArg<'_>> = substs
.into_iter()
.map(|arg| {
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() {
@ -1125,15 +1129,11 @@ fn suggest_associated_call_syntax(
} else {
arg
}
})
.collect::<Vec<_>>();
}));
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())

View File

@ -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
}

View File

@ -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
}

View File

@ -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`.