mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 18:23:49 +00:00
suggestion if struct field has method
This commit is contained in:
parent
18f314e702
commit
dff7f25981
@ -2277,14 +2277,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// try to add a suggestion in case the field is a nested field of a field of the Adt
|
||||
if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) {
|
||||
for candidate_field in fields.iter() {
|
||||
if let Some(field_path) = self.check_for_nested_field(
|
||||
if let Some(mut field_path) = self.check_for_nested_field_satisfying(
|
||||
span,
|
||||
field,
|
||||
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
|
||||
candidate_field,
|
||||
substs,
|
||||
vec![],
|
||||
self.tcx.parent_module(id).to_def_id(),
|
||||
) {
|
||||
// field_path includes `field` that we're looking for, so pop it.
|
||||
field_path.pop();
|
||||
|
||||
let field_path_str = field_path
|
||||
.iter()
|
||||
.map(|id| id.name.to_ident_string())
|
||||
@ -2304,7 +2307,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
err
|
||||
}
|
||||
|
||||
fn get_field_candidates(
|
||||
crate fn get_field_candidates(
|
||||
&self,
|
||||
span: Span,
|
||||
base_t: Ty<'tcx>,
|
||||
@ -2329,49 +2332,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
/// This method is called after we have encountered a missing field error to recursively
|
||||
/// search for the field
|
||||
fn check_for_nested_field(
|
||||
crate fn check_for_nested_field_satisfying(
|
||||
&self,
|
||||
span: Span,
|
||||
target_field: Ident,
|
||||
matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool,
|
||||
candidate_field: &ty::FieldDef,
|
||||
subst: SubstsRef<'tcx>,
|
||||
mut field_path: Vec<Ident>,
|
||||
id: DefId,
|
||||
) -> Option<Vec<Ident>> {
|
||||
debug!(
|
||||
"check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}",
|
||||
"check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
|
||||
span, candidate_field, field_path
|
||||
);
|
||||
|
||||
if candidate_field.ident(self.tcx) == target_field {
|
||||
Some(field_path)
|
||||
} else if field_path.len() > 3 {
|
||||
if field_path.len() > 3 {
|
||||
// For compile-time reasons and to avoid infinite recursion we only check for fields
|
||||
// up to a depth of three
|
||||
None
|
||||
} else {
|
||||
// recursively search fields of `candidate_field` if it's a ty::Adt
|
||||
|
||||
field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
|
||||
let field_ty = candidate_field.ty(self.tcx, subst);
|
||||
if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) {
|
||||
for field in nested_fields.iter() {
|
||||
let accessible = field.vis.is_accessible_from(id, self.tcx);
|
||||
if accessible {
|
||||
let ident = field.ident(self.tcx).normalize_to_macros_2_0();
|
||||
if ident == target_field {
|
||||
if field.vis.is_accessible_from(id, self.tcx) {
|
||||
if matches(candidate_field, field_ty) {
|
||||
return Some(field_path);
|
||||
}
|
||||
let field_path = field_path.clone();
|
||||
if let Some(path) = self.check_for_nested_field(
|
||||
} else if let Some(field_path) = self.check_for_nested_field_satisfying(
|
||||
span,
|
||||
target_field,
|
||||
matches,
|
||||
field,
|
||||
subst,
|
||||
field_path,
|
||||
field_path.clone(),
|
||||
id,
|
||||
) {
|
||||
return Some(path);
|
||||
return Some(field_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ use rustc_trait_selection::traits::{
|
||||
use std::cmp::Ordering;
|
||||
use std::iter;
|
||||
|
||||
use super::probe::Mode;
|
||||
use super::probe::{Mode, ProbeScope};
|
||||
use super::{CandidateSource, MethodError, NoMatchData};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
@ -1129,6 +1129,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
label_span_not_found();
|
||||
}
|
||||
|
||||
if let SelfSource::MethodCall(expr) = source
|
||||
&& let Some((fields, substs)) = self.get_field_candidates(span, actual)
|
||||
{
|
||||
let call_expr =
|
||||
self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
|
||||
for candidate_field in fields.iter() {
|
||||
if let Some(field_path) = self.check_for_nested_field_satisfying(
|
||||
span,
|
||||
&|_, field_ty| {
|
||||
self.lookup_probe(
|
||||
span,
|
||||
item_name,
|
||||
field_ty,
|
||||
call_expr,
|
||||
ProbeScope::AllTraits,
|
||||
)
|
||||
.is_ok()
|
||||
},
|
||||
candidate_field,
|
||||
substs,
|
||||
vec![],
|
||||
self.tcx.parent_module(expr.hir_id).to_def_id(),
|
||||
) {
|
||||
let field_path_str = field_path
|
||||
.iter()
|
||||
.map(|id| id.name.to_ident_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(".");
|
||||
debug!("field_path_str: {:?}", field_path_str);
|
||||
|
||||
err.span_suggestion_verbose(
|
||||
item_name.span.shrink_to_lo(),
|
||||
"one of the expressions' fields has a method of the same name",
|
||||
format!("{field_path_str}."),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bound_spans.sort();
|
||||
bound_spans.dedup();
|
||||
for (span, msg) in bound_spans.into_iter() {
|
||||
|
@ -18,6 +18,10 @@ note: the following trait bounds were not satisfied:
|
||||
|
|
||||
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
||||
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
||||
help: one of the expressions' fields has a method of the same name
|
||||
|
|
||||
LL | let filter = map.stream.filterx(|x: &_| true);
|
||||
| +++++++
|
||||
|
||||
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
|
||||
--> $DIR/issue-30786.rs:140:24
|
||||
@ -39,6 +43,10 @@ note: the following trait bounds were not satisfied:
|
||||
|
|
||||
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
||||
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
||||
help: one of the expressions' fields has a method of the same name
|
||||
|
|
||||
LL | let count = filter.stream.countx();
|
||||
| +++++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -18,6 +18,10 @@ note: the following trait bounds were not satisfied:
|
||||
|
|
||||
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
||||
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
||||
help: one of the expressions' fields has a method of the same name
|
||||
|
|
||||
LL | let filter = map.stream.filterx(|x: &_| true);
|
||||
| +++++++
|
||||
|
||||
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
|
||||
--> $DIR/issue-30786.rs:140:24
|
||||
@ -39,6 +43,10 @@ note: the following trait bounds were not satisfied:
|
||||
|
|
||||
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
||||
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
||||
help: one of the expressions' fields has a method of the same name
|
||||
|
|
||||
LL | let count = filter.stream.countx();
|
||||
| +++++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
23
src/test/ui/suggestions/field-has-method.rs
Normal file
23
src/test/ui/suggestions/field-has-method.rs
Normal file
@ -0,0 +1,23 @@
|
||||
struct Kind;
|
||||
|
||||
struct Ty {
|
||||
kind: Kind,
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
fn kind(&self) -> Kind {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
struct InferOk<T> {
|
||||
value: T,
|
||||
predicates: Vec<()>,
|
||||
}
|
||||
|
||||
fn foo(i: InferOk<Ty>) {
|
||||
let k = i.kind();
|
||||
//~^ no method named `kind` found for struct `InferOk` in the current scope
|
||||
}
|
||||
|
||||
fn main() {}
|
17
src/test/ui/suggestions/field-has-method.stderr
Normal file
17
src/test/ui/suggestions/field-has-method.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
error[E0599]: no method named `kind` found for struct `InferOk` in the current scope
|
||||
--> $DIR/field-has-method.rs:19:15
|
||||
|
|
||||
LL | struct InferOk<T> {
|
||||
| ----------------- method `kind` not found for this
|
||||
...
|
||||
LL | let k = i.kind();
|
||||
| ^^^^ method not found in `InferOk<Ty>`
|
||||
|
|
||||
help: one of the expressions' fields has a method of the same name
|
||||
|
|
||||
LL | let k = i.value.kind();
|
||||
| ++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
Loading…
Reference in New Issue
Block a user