Do not report too many expr field candidates
This commit is contained in:
parent
015a824f2d
commit
c3f568b331
8 changed files with 158 additions and 67 deletions
|
@ -157,6 +157,7 @@ symbols! {
|
||||||
BTreeSet,
|
BTreeSet,
|
||||||
BinaryHeap,
|
BinaryHeap,
|
||||||
Borrow,
|
Borrow,
|
||||||
|
BorrowMut,
|
||||||
Break,
|
Break,
|
||||||
C,
|
C,
|
||||||
CStr,
|
CStr,
|
||||||
|
|
|
@ -2588,32 +2588,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if let Some((fields, substs)) =
|
if let Some((fields, substs)) =
|
||||||
self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
|
self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
|
||||||
{
|
{
|
||||||
for candidate_field in fields {
|
let candidate_fields: Vec<_> = fields
|
||||||
if let Some(mut field_path) = self.check_for_nested_field_satisfying(
|
.filter_map(|candidate_field| {
|
||||||
span,
|
self.check_for_nested_field_satisfying(
|
||||||
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
|
span,
|
||||||
candidate_field,
|
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
|
||||||
substs,
|
candidate_field,
|
||||||
vec![],
|
substs,
|
||||||
mod_id,
|
vec![],
|
||||||
) {
|
mod_id,
|
||||||
// field_path includes `field` that we're looking for, so pop it.
|
)
|
||||||
|
})
|
||||||
|
.map(|mut field_path| {
|
||||||
field_path.pop();
|
field_path.pop();
|
||||||
|
field_path
|
||||||
let field_path_str = field_path
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|id| id.name.to_ident_string())
|
.map(|id| id.name.to_ident_string())
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join(".");
|
.join(".")
|
||||||
debug!("field_path_str: {:?}", field_path_str);
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
err.span_suggestion_verbose(
|
let len = candidate_fields.len();
|
||||||
field.span.shrink_to_lo(),
|
if len > 0 {
|
||||||
"one of the expressions' fields has a field of the same name",
|
err.span_suggestions(
|
||||||
format!("{field_path_str}."),
|
field.span.shrink_to_lo(),
|
||||||
Applicability::MaybeIncorrect,
|
format!(
|
||||||
);
|
"{} of the expressions' fields {} a field of the same name",
|
||||||
}
|
if len > 1 { "some" } else { "one" },
|
||||||
|
if len > 1 { "have" } else { "has" },
|
||||||
|
),
|
||||||
|
candidate_fields.iter().map(|path| format!("{path}.")),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err
|
err
|
||||||
|
|
|
@ -1338,42 +1338,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
item_name: Ident,
|
item_name: Ident,
|
||||||
) {
|
) {
|
||||||
if let SelfSource::MethodCall(expr) = source
|
if let SelfSource::MethodCall(expr) = source
|
||||||
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
|
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
|
||||||
&& let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id)
|
&& let Some((fields, substs)) =
|
||||||
|
self.get_field_candidates_considering_privacy(span, actual, mod_id)
|
||||||
{
|
{
|
||||||
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
|
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
|
||||||
for candidate_field in fields {
|
|
||||||
if let Some(field_path) = self.check_for_nested_field_satisfying(
|
let lang_items = self.tcx.lang_items();
|
||||||
span,
|
let never_mention_traits = [
|
||||||
&|_, field_ty| {
|
lang_items.clone_trait(),
|
||||||
self.lookup_probe(
|
lang_items.deref_trait(),
|
||||||
span,
|
lang_items.deref_mut_trait(),
|
||||||
item_name,
|
self.tcx.get_diagnostic_item(sym::AsRef),
|
||||||
field_ty,
|
self.tcx.get_diagnostic_item(sym::AsMut),
|
||||||
call_expr,
|
self.tcx.get_diagnostic_item(sym::Borrow),
|
||||||
ProbeScope::AllTraits,
|
self.tcx.get_diagnostic_item(sym::BorrowMut),
|
||||||
)
|
];
|
||||||
.is_ok()
|
let candidate_fields: Vec<_> = fields
|
||||||
},
|
.filter_map(|candidate_field| {
|
||||||
candidate_field,
|
self.check_for_nested_field_satisfying(
|
||||||
substs,
|
span,
|
||||||
vec![],
|
&|_, field_ty| {
|
||||||
mod_id,
|
self.lookup_probe(
|
||||||
) {
|
span,
|
||||||
let field_path_str = field_path
|
item_name,
|
||||||
|
field_ty,
|
||||||
|
call_expr,
|
||||||
|
ProbeScope::TraitsInScope,
|
||||||
|
)
|
||||||
|
.map_or(false, |pick| {
|
||||||
|
!never_mention_traits
|
||||||
|
.iter()
|
||||||
|
.flatten()
|
||||||
|
.any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
candidate_field,
|
||||||
|
substs,
|
||||||
|
vec![],
|
||||||
|
mod_id,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(|field_path| {
|
||||||
|
field_path
|
||||||
.iter()
|
.iter()
|
||||||
.map(|id| id.name.to_ident_string())
|
.map(|id| id.name.to_ident_string())
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join(".");
|
.join(".")
|
||||||
debug!("field_path_str: {:?}", field_path_str);
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
err.span_suggestion_verbose(
|
let len = candidate_fields.len();
|
||||||
item_name.span.shrink_to_lo(),
|
if len > 0 {
|
||||||
"one of the expressions' fields has a method of the same name",
|
err.span_suggestions(
|
||||||
format!("{field_path_str}."),
|
item_name.span.shrink_to_lo(),
|
||||||
Applicability::MaybeIncorrect,
|
format!(
|
||||||
);
|
"{} of the expressions' fields {} a method of the same name",
|
||||||
}
|
if len > 1 { "some" } else { "one" },
|
||||||
|
if len > 1 { "have" } else { "has" },
|
||||||
|
),
|
||||||
|
candidate_fields.iter().map(|path| format!("{path}.")),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,6 @@ LL | let _y = x.clone();
|
||||||
= help: items from traits can only be used if the trait is implemented and in scope
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
= note: the following trait defines an item `clone`, perhaps you need to implement it:
|
= note: the following trait defines an item `clone`, perhaps you need to implement it:
|
||||||
candidate #1: `Clone`
|
candidate #1: `Clone`
|
||||||
help: one of the expressions' fields has a method of the same name
|
|
||||||
|
|
|
||||||
LL | let _y = x.i.clone();
|
|
||||||
| ++
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,6 @@ LL | let _d = c.clone();
|
||||||
= help: items from traits can only be used if the trait is implemented and in scope
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
= note: the following trait defines an item `clone`, perhaps you need to implement it:
|
= note: the following trait defines an item `clone`, perhaps you need to implement it:
|
||||||
candidate #1: `Clone`
|
candidate #1: `Clone`
|
||||||
help: one of the expressions' fields has a method of the same name
|
|
||||||
|
|
|
||||||
LL | let _d = c.x.clone();
|
|
||||||
| ++
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,6 @@ LL | let _y = x.clone();
|
||||||
= help: items from traits can only be used if the trait is implemented and in scope
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
= note: the following trait defines an item `clone`, perhaps you need to implement it:
|
= note: the following trait defines an item `clone`, perhaps you need to implement it:
|
||||||
candidate #1: `Clone`
|
candidate #1: `Clone`
|
||||||
help: one of the expressions' fields has a method of the same name
|
|
||||||
|
|
|
||||||
LL | let _y = x.i.clone();
|
|
||||||
| ++
|
|
||||||
help: one of the expressions' fields has a method of the same name
|
|
||||||
|
|
|
||||||
LL | let _y = x.j.x.clone();
|
|
||||||
| ++++
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
29
src/test/ui/suggestions/too-many-field-suggestions.rs
Normal file
29
src/test/ui/suggestions/too-many-field-suggestions.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
struct Thing {
|
||||||
|
a0: Foo,
|
||||||
|
a1: Foo,
|
||||||
|
a2: Foo,
|
||||||
|
a3: Foo,
|
||||||
|
a4: Foo,
|
||||||
|
a5: Foo,
|
||||||
|
a6: Foo,
|
||||||
|
a7: Foo,
|
||||||
|
a8: Foo,
|
||||||
|
a9: Foo,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
field: Field,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Field;
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
fn bar(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(t: Thing) {
|
||||||
|
t.bar(); //~ ERROR no method named `bar` found for struct `Thing`
|
||||||
|
t.field; //~ ERROR no field `field` on type `Thing`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
44
src/test/ui/suggestions/too-many-field-suggestions.stderr
Normal file
44
src/test/ui/suggestions/too-many-field-suggestions.stderr
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
error[E0599]: no method named `bar` found for struct `Thing` in the current scope
|
||||||
|
--> $DIR/too-many-field-suggestions.rs:25:7
|
||||||
|
|
|
||||||
|
LL | struct Thing {
|
||||||
|
| ------------ method `bar` not found for this struct
|
||||||
|
...
|
||||||
|
LL | t.bar();
|
||||||
|
| ^^^ method not found in `Thing`
|
||||||
|
|
|
||||||
|
help: some of the expressions' fields have a method of the same name
|
||||||
|
|
|
||||||
|
LL | t.a0.bar();
|
||||||
|
| +++
|
||||||
|
LL | t.a1.bar();
|
||||||
|
| +++
|
||||||
|
LL | t.a2.bar();
|
||||||
|
| +++
|
||||||
|
LL | t.a3.bar();
|
||||||
|
| +++
|
||||||
|
and 6 other candidates
|
||||||
|
|
||||||
|
error[E0609]: no field `field` on type `Thing`
|
||||||
|
--> $DIR/too-many-field-suggestions.rs:26:7
|
||||||
|
|
|
||||||
|
LL | t.field;
|
||||||
|
| ^^^^^ unknown field
|
||||||
|
|
|
||||||
|
= note: available fields are: `a0`, `a1`, `a2`, `a3`, `a4` ... and 5 others
|
||||||
|
help: some of the expressions' fields have a field of the same name
|
||||||
|
|
|
||||||
|
LL | t.a0.field;
|
||||||
|
| +++
|
||||||
|
LL | t.a1.field;
|
||||||
|
| +++
|
||||||
|
LL | t.a2.field;
|
||||||
|
| +++
|
||||||
|
LL | t.a3.field;
|
||||||
|
| +++
|
||||||
|
and 6 other candidates
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0599, E0609.
|
||||||
|
For more information about an error, try `rustc --explain E0599`.
|
Loading…
Add table
Reference in a new issue