Skip to content

Commit 5497317

Browse files
Do autoderef to match impl against rcvr
1 parent bf607da commit 5497317

File tree

4 files changed

+95
-46
lines changed

4 files changed

+95
-46
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+46-46
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@ use rustc_infer::infer::{
2020
};
2121
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
2222
use rustc_middle::traits::util::supertraits;
23+
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
2324
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
2425
use rustc_middle::ty::print::with_crate_prefix;
25-
use rustc_middle::ty::{
26-
self, DefIdTree, GenericArg, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable,
27-
};
26+
use rustc_middle::ty::{self, DefIdTree, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable};
2827
use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
2928
use rustc_span::symbol::{kw, sym, Ident};
3029
use rustc_span::Symbol;
@@ -1090,50 +1089,51 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10901089
// When the "method" is resolved through dereferencing, we really want the
10911090
// original type that has the associated function for accurate suggestions.
10921091
// (#61411)
1093-
let ty = self.tcx.type_of(*impl_did);
1094-
match (&ty.peel_refs().kind(), &rcvr_ty.peel_refs().kind()) {
1095-
(ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => {
1096-
// If there are any inferred arguments, (`{integer}`), we should replace
1097-
// them with underscores to allow the compiler to infer them
1098-
let infer_substs: Vec<GenericArg<'_>> = substs
1099-
.into_iter()
1100-
.map(|arg| {
1101-
if !arg.is_suggestable(self.tcx, true) {
1102-
has_unsuggestable_args = true;
1103-
match arg.unpack() {
1104-
GenericArgKind::Lifetime(_) => self
1105-
.next_region_var(RegionVariableOrigin::MiscVariable(
1106-
rustc_span::DUMMY_SP,
1107-
))
1108-
.into(),
1109-
GenericArgKind::Type(_) => self
1110-
.next_ty_var(TypeVariableOrigin {
1111-
span: rustc_span::DUMMY_SP,
1112-
kind: TypeVariableOriginKind::MiscVariable,
1113-
})
1114-
.into(),
1115-
GenericArgKind::Const(arg) => self
1116-
.next_const_var(
1117-
arg.ty(),
1118-
ConstVariableOrigin {
1119-
span: rustc_span::DUMMY_SP,
1120-
kind: ConstVariableOriginKind::MiscVariable,
1121-
},
1122-
)
1123-
.into(),
1124-
}
1125-
} else {
1126-
arg
1127-
}
1128-
})
1129-
.collect::<Vec<_>>();
1092+
let impl_ty = self.tcx.type_of(*impl_did);
1093+
let target_ty = self
1094+
.autoderef(sugg_span, rcvr_ty)
1095+
.find(|(rcvr_ty, _)| {
1096+
DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }
1097+
.types_may_unify(*rcvr_ty, impl_ty)
1098+
})
1099+
.map_or(impl_ty, |(ty, _)| ty)
1100+
.peel_refs();
1101+
if let ty::Adt(def, substs) = target_ty.kind() {
1102+
// If there are any inferred arguments, (`{integer}`), we should replace
1103+
// them with underscores to allow the compiler to infer them
1104+
let infer_substs = self.tcx.mk_substs(substs.into_iter().map(|arg| {
1105+
if !arg.is_suggestable(self.tcx, true) {
1106+
has_unsuggestable_args = true;
1107+
match arg.unpack() {
1108+
GenericArgKind::Lifetime(_) => self
1109+
.next_region_var(RegionVariableOrigin::MiscVariable(
1110+
rustc_span::DUMMY_SP,
1111+
))
1112+
.into(),
1113+
GenericArgKind::Type(_) => self
1114+
.next_ty_var(TypeVariableOrigin {
1115+
span: rustc_span::DUMMY_SP,
1116+
kind: TypeVariableOriginKind::MiscVariable,
1117+
})
1118+
.into(),
1119+
GenericArgKind::Const(arg) => self
1120+
.next_const_var(
1121+
arg.ty(),
1122+
ConstVariableOrigin {
1123+
span: rustc_span::DUMMY_SP,
1124+
kind: ConstVariableOriginKind::MiscVariable,
1125+
},
1126+
)
1127+
.into(),
1128+
}
1129+
} else {
1130+
arg
1131+
}
1132+
}));
11301133

1131-
self.tcx.value_path_str_with_substs(
1132-
def_actual.did(),
1133-
self.tcx.intern_substs(&infer_substs),
1134-
)
1135-
}
1136-
_ => self.ty_to_value_string(ty.peel_refs()),
1134+
self.tcx.value_path_str_with_substs(def.did(), infer_substs)
1135+
} else {
1136+
self.ty_to_value_string(target_ty)
11371137
}
11381138
} else {
11391139
self.ty_to_value_string(rcvr_ty.peel_refs())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
3+
#![allow(unused)]
4+
5+
struct Foo<T>(T);
6+
7+
impl<T> Foo<T> {
8+
fn test() -> i32 { 1 }
9+
}
10+
11+
fn main() {
12+
let x = Box::new(Foo(1i32));
13+
Foo::<i32>::test();
14+
//~^ ERROR no method named `test` found for struct `Box<Foo<i32>>` in the current scope
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
3+
#![allow(unused)]
4+
5+
struct Foo<T>(T);
6+
7+
impl<T> Foo<T> {
8+
fn test() -> i32 { 1 }
9+
}
10+
11+
fn main() {
12+
let x = Box::new(Foo(1i32));
13+
x.test();
14+
//~^ ERROR no method named `test` found for struct `Box<Foo<i32>>` in the current scope
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0599]: no method named `test` found for struct `Box<Foo<i32>>` in the current scope
2+
--> $DIR/suggest-assoc-fn-call-deref.rs:13:7
3+
|
4+
LL | x.test();
5+
| --^^^^--
6+
| | |
7+
| | this is an associated function, not a method
8+
| help: use associated function syntax instead: `Foo::<i32>::test()`
9+
|
10+
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
11+
note: the candidate is defined in an impl for the type `Foo<T>`
12+
--> $DIR/suggest-assoc-fn-call-deref.rs:8:5
13+
|
14+
LL | fn test() -> i32 { 1 }
15+
| ^^^^^^^^^^^^^^^^
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)