Skip to content

Commit c3f568b

Browse files
Do not report too many expr field candidates
1 parent 015a824 commit c3f568b

File tree

8 files changed

+160
-69
lines changed

8 files changed

+160
-69
lines changed

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ symbols! {
157157
BTreeSet,
158158
BinaryHeap,
159159
Borrow,
160+
BorrowMut,
160161
Break,
161162
C,
162163
CStr,

compiler/rustc_typeck/src/check/expr.rs

+29-22
Original file line numberDiff line numberDiff line change
@@ -2588,32 +2588,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25882588
if let Some((fields, substs)) =
25892589
self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
25902590
{
2591-
for candidate_field in fields {
2592-
if let Some(mut field_path) = self.check_for_nested_field_satisfying(
2593-
span,
2594-
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
2595-
candidate_field,
2596-
substs,
2597-
vec![],
2598-
mod_id,
2599-
) {
2600-
// field_path includes `field` that we're looking for, so pop it.
2591+
let candidate_fields: Vec<_> = fields
2592+
.filter_map(|candidate_field| {
2593+
self.check_for_nested_field_satisfying(
2594+
span,
2595+
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
2596+
candidate_field,
2597+
substs,
2598+
vec![],
2599+
mod_id,
2600+
)
2601+
})
2602+
.map(|mut field_path| {
26012603
field_path.pop();
2602-
2603-
let field_path_str = field_path
2604+
field_path
26042605
.iter()
26052606
.map(|id| id.name.to_ident_string())
26062607
.collect::<Vec<String>>()
2607-
.join(".");
2608-
debug!("field_path_str: {:?}", field_path_str);
2609-
2610-
err.span_suggestion_verbose(
2611-
field.span.shrink_to_lo(),
2612-
"one of the expressions' fields has a field of the same name",
2613-
format!("{field_path_str}."),
2614-
Applicability::MaybeIncorrect,
2615-
);
2616-
}
2608+
.join(".")
2609+
})
2610+
.collect::<Vec<_>>();
2611+
2612+
let len = candidate_fields.len();
2613+
if len > 0 {
2614+
err.span_suggestions(
2615+
field.span.shrink_to_lo(),
2616+
format!(
2617+
"{} of the expressions' fields {} a field of the same name",
2618+
if len > 1 { "some" } else { "one" },
2619+
if len > 1 { "have" } else { "has" },
2620+
),
2621+
candidate_fields.iter().map(|path| format!("{path}.")),
2622+
Applicability::MaybeIncorrect,
2623+
);
26172624
}
26182625
}
26192626
err

compiler/rustc_typeck/src/check/method/suggest.rs

+57-31
Original file line numberDiff line numberDiff line change
@@ -1338,42 +1338,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13381338
item_name: Ident,
13391339
) {
13401340
if let SelfSource::MethodCall(expr) = source
1341-
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
1342-
&& let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id)
1341+
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
1342+
&& let Some((fields, substs)) =
1343+
self.get_field_candidates_considering_privacy(span, actual, mod_id)
13431344
{
13441345
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
1345-
for candidate_field in fields {
1346-
if let Some(field_path) = self.check_for_nested_field_satisfying(
1347-
span,
1348-
&|_, field_ty| {
1349-
self.lookup_probe(
1350-
span,
1351-
item_name,
1352-
field_ty,
1353-
call_expr,
1354-
ProbeScope::AllTraits,
1355-
)
1356-
.is_ok()
1357-
},
1358-
candidate_field,
1359-
substs,
1360-
vec![],
1361-
mod_id,
1362-
) {
1363-
let field_path_str = field_path
1346+
1347+
let lang_items = self.tcx.lang_items();
1348+
let never_mention_traits = [
1349+
lang_items.clone_trait(),
1350+
lang_items.deref_trait(),
1351+
lang_items.deref_mut_trait(),
1352+
self.tcx.get_diagnostic_item(sym::AsRef),
1353+
self.tcx.get_diagnostic_item(sym::AsMut),
1354+
self.tcx.get_diagnostic_item(sym::Borrow),
1355+
self.tcx.get_diagnostic_item(sym::BorrowMut),
1356+
];
1357+
let candidate_fields: Vec<_> = fields
1358+
.filter_map(|candidate_field| {
1359+
self.check_for_nested_field_satisfying(
1360+
span,
1361+
&|_, field_ty| {
1362+
self.lookup_probe(
1363+
span,
1364+
item_name,
1365+
field_ty,
1366+
call_expr,
1367+
ProbeScope::TraitsInScope,
1368+
)
1369+
.map_or(false, |pick| {
1370+
!never_mention_traits
1371+
.iter()
1372+
.flatten()
1373+
.any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id)
1374+
})
1375+
},
1376+
candidate_field,
1377+
substs,
1378+
vec![],
1379+
mod_id,
1380+
)
1381+
})
1382+
.map(|field_path| {
1383+
field_path
13641384
.iter()
13651385
.map(|id| id.name.to_ident_string())
13661386
.collect::<Vec<String>>()
1367-
.join(".");
1368-
debug!("field_path_str: {:?}", field_path_str);
1369-
1370-
err.span_suggestion_verbose(
1371-
item_name.span.shrink_to_lo(),
1372-
"one of the expressions' fields has a method of the same name",
1373-
format!("{field_path_str}."),
1374-
Applicability::MaybeIncorrect,
1375-
);
1376-
}
1387+
.join(".")
1388+
})
1389+
.collect();
1390+
1391+
let len = candidate_fields.len();
1392+
if len > 0 {
1393+
err.span_suggestions(
1394+
item_name.span.shrink_to_lo(),
1395+
format!(
1396+
"{} of the expressions' fields {} a method of the same name",
1397+
if len > 1 { "some" } else { "one" },
1398+
if len > 1 { "have" } else { "has" },
1399+
),
1400+
candidate_fields.iter().map(|path| format!("{path}.")),
1401+
Applicability::MaybeIncorrect,
1402+
);
13771403
}
13781404
}
13791405
}

src/test/ui/copy-a-resource.stderr

-4
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ LL | let _y = x.clone();
1010
= help: items from traits can only be used if the trait is implemented and in scope
1111
= note: the following trait defines an item `clone`, perhaps you need to implement it:
1212
candidate #1: `Clone`
13-
help: one of the expressions' fields has a method of the same name
14-
|
15-
LL | let _y = x.i.clone();
16-
| ++
1713

1814
error: aborting due to previous error
1915

src/test/ui/issues/issue-2823.stderr

-4
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ LL | let _d = c.clone();
1010
= help: items from traits can only be used if the trait is implemented and in scope
1111
= note: the following trait defines an item `clone`, perhaps you need to implement it:
1212
candidate #1: `Clone`
13-
help: one of the expressions' fields has a method of the same name
14-
|
15-
LL | let _d = c.x.clone();
16-
| ++
1713

1814
error: aborting due to previous error
1915

src/test/ui/noncopyable-class.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@ LL | let _y = x.clone();
1010
= help: items from traits can only be used if the trait is implemented and in scope
1111
= note: the following trait defines an item `clone`, perhaps you need to implement it:
1212
candidate #1: `Clone`
13-
help: one of the expressions' fields has a method of the same name
14-
|
15-
LL | let _y = x.i.clone();
16-
| ++
17-
help: one of the expressions' fields has a method of the same name
18-
|
19-
LL | let _y = x.j.x.clone();
20-
| ++++
2113

2214
error: aborting due to previous error
2315

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
struct Thing {
2+
a0: Foo,
3+
a1: Foo,
4+
a2: Foo,
5+
a3: Foo,
6+
a4: Foo,
7+
a5: Foo,
8+
a6: Foo,
9+
a7: Foo,
10+
a8: Foo,
11+
a9: Foo,
12+
}
13+
14+
struct Foo {
15+
field: Field,
16+
}
17+
18+
struct Field;
19+
20+
impl Foo {
21+
fn bar(&self) {}
22+
}
23+
24+
fn bar(t: Thing) {
25+
t.bar(); //~ ERROR no method named `bar` found for struct `Thing`
26+
t.field; //~ ERROR no field `field` on type `Thing`
27+
}
28+
29+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error[E0599]: no method named `bar` found for struct `Thing` in the current scope
2+
--> $DIR/too-many-field-suggestions.rs:25:7
3+
|
4+
LL | struct Thing {
5+
| ------------ method `bar` not found for this struct
6+
...
7+
LL | t.bar();
8+
| ^^^ method not found in `Thing`
9+
|
10+
help: some of the expressions' fields have a method of the same name
11+
|
12+
LL | t.a0.bar();
13+
| +++
14+
LL | t.a1.bar();
15+
| +++
16+
LL | t.a2.bar();
17+
| +++
18+
LL | t.a3.bar();
19+
| +++
20+
and 6 other candidates
21+
22+
error[E0609]: no field `field` on type `Thing`
23+
--> $DIR/too-many-field-suggestions.rs:26:7
24+
|
25+
LL | t.field;
26+
| ^^^^^ unknown field
27+
|
28+
= note: available fields are: `a0`, `a1`, `a2`, `a3`, `a4` ... and 5 others
29+
help: some of the expressions' fields have a field of the same name
30+
|
31+
LL | t.a0.field;
32+
| +++
33+
LL | t.a1.field;
34+
| +++
35+
LL | t.a2.field;
36+
| +++
37+
LL | t.a3.field;
38+
| +++
39+
and 6 other candidates
40+
41+
error: aborting due to 2 previous errors
42+
43+
Some errors have detailed explanations: E0599, E0609.
44+
For more information about an error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)