Skip to content

Commit a291d4e

Browse files
committed
convert field/method confusion help to suggestions
1 parent 16e7e05 commit a291d4e

File tree

5 files changed

+98
-53
lines changed

5 files changed

+98
-53
lines changed

src/librustc_typeck/check/method/suggest.rs

+50-33
Original file line numberDiff line numberDiff line change
@@ -332,44 +332,61 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
332332
// If the method name is the name of a field with a function or closure type,
333333
// give a helping note that it has to be called as `(x.f)(...)`.
334334
if let SelfSource::MethodCall(expr) = source {
335-
for (ty, _) in self.autoderef(span, rcvr_ty) {
336-
if let ty::Adt(def, substs) = ty.sty {
337-
if !def.is_enum() {
335+
let field_receiver = self
336+
.autoderef(span, rcvr_ty)
337+
.find_map(|(ty, _)| match ty.sty {
338+
ty::Adt(def, substs) if !def.is_enum() => {
338339
let variant = &def.non_enum_variant();
339-
if let Some(index) = self.tcx.find_field_index(item_name, variant) {
340+
self.tcx.find_field_index(item_name, variant).map(|index| {
340341
let field = &variant.fields[index];
341-
let snippet = tcx.sess.source_map().span_to_snippet(expr.span);
342-
let expr_string = match snippet {
343-
Ok(expr_string) => expr_string,
344-
_ => "s".into(), // Default to a generic placeholder for the
345-
// expression when we can't generate a
346-
// string snippet.
347-
};
348-
349342
let field_ty = field.ty(tcx, substs);
350-
let scope = self.tcx.hir().get_module_parent_by_hir_id(
351-
self.body_id);
352-
if field.vis.is_accessible_from(scope, self.tcx) {
353-
if self.is_fn_ty(&field_ty, span) {
354-
err.help(&format!("use `({0}.{1})(...)` if you \
355-
meant to call the function \
356-
stored in the `{1}` field",
357-
expr_string,
358-
item_name));
359-
} else {
360-
err.help(&format!("did you mean to write `{0}.{1}` \
361-
instead of `{0}.{1}(...)`?",
362-
expr_string,
363-
item_name));
364-
}
365-
err.span_label(span, "field, not a method");
366-
} else {
367-
err.span_label(span, "private field, not a method");
368-
}
369-
break;
370-
}
343+
(field, field_ty)
344+
})
345+
}
346+
_ => None,
347+
});
348+
349+
if let Some((field, field_ty)) = field_receiver {
350+
let scope = self.tcx.hir().get_module_parent_by_hir_id(self.body_id);
351+
let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
352+
353+
if is_accessible {
354+
if self.is_fn_ty(&field_ty, span) {
355+
let expr_span = expr.span.to(item_name.span);
356+
err.multipart_suggestion(
357+
&format!(
358+
"to call the function stored in `{}`, \
359+
surround the field access with parentheses",
360+
item_name,
361+
),
362+
vec![
363+
(expr_span.shrink_to_lo(), '('.to_string()),
364+
(expr_span.shrink_to_hi(), ')'.to_string()),
365+
],
366+
Applicability::MachineApplicable,
367+
);
368+
} else {
369+
let call_expr = self.tcx.hir().expect_expr_by_hir_id(
370+
self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id),
371+
);
372+
373+
let span = call_expr.span.trim_start(item_name.span).unwrap();
374+
375+
err.span_suggestion(
376+
span,
377+
"remove the arguments",
378+
String::new(),
379+
Applicability::MaybeIncorrect,
380+
);
371381
}
372382
}
383+
384+
let field_kind = if is_accessible {
385+
"field"
386+
} else {
387+
"private field"
388+
};
389+
err.span_label(item_name.span, format!("{}, not a method", field_kind));
373390
}
374391
} else {
375392
err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));

src/test/ui/confuse-field-and-method/issue-18343.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ LL | struct Obj<F> where F: FnMut() -> u32 {
66
...
77
LL | o.closure();
88
| ^^^^^^^ field, not a method
9+
help: to call the function stored in `closure`, surround the field access with parentheses
910
|
10-
= help: use `(o.closure)(...)` if you meant to call the function stored in the `closure` field
11+
LL | (o.closure)();
12+
| ^ ^
1113

1214
error: aborting due to previous error
1315

src/test/ui/confuse-field-and-method/issue-2392.stderr

+33-15
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ LL | struct Obj<F> where F: FnOnce() -> u32 {
66
...
77
LL | o_closure.closure();
88
| ^^^^^^^ field, not a method
9+
help: to call the function stored in `closure`, surround the field access with parentheses
910
|
10-
= help: use `(o_closure.closure)(...)` if you meant to call the function stored in the `closure` field
11+
LL | (o_closure.closure)();
12+
| ^ ^
1113

1214
error[E0599]: no method named `not_closure` found for type `Obj<[closure@$DIR/issue-2392.rs:39:36: 39:41]>` in the current scope
1315
--> $DIR/issue-2392.rs:42:15
@@ -16,9 +18,9 @@ LL | struct Obj<F> where F: FnOnce() -> u32 {
1618
| -------------------------------------- method `not_closure` not found for this
1719
...
1820
LL | o_closure.not_closure();
19-
| ^^^^^^^^^^^ field, not a method
20-
|
21-
= help: did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`?
21+
| ^^^^^^^^^^^-- help: remove the arguments
22+
| |
23+
| field, not a method
2224

2325
error[E0599]: no method named `closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
2426
--> $DIR/issue-2392.rs:46:12
@@ -28,8 +30,10 @@ LL | struct Obj<F> where F: FnOnce() -> u32 {
2830
...
2931
LL | o_func.closure();
3032
| ^^^^^^^ field, not a method
33+
help: to call the function stored in `closure`, surround the field access with parentheses
3134
|
32-
= help: use `(o_func.closure)(...)` if you meant to call the function stored in the `closure` field
35+
LL | (o_func.closure)();
36+
| ^ ^
3337

3438
error[E0599]: no method named `boxed_closure` found for type `BoxedObj` in the current scope
3539
--> $DIR/issue-2392.rs:49:14
@@ -39,8 +43,10 @@ LL | struct BoxedObj {
3943
...
4044
LL | boxed_fn.boxed_closure();
4145
| ^^^^^^^^^^^^^ field, not a method
46+
help: to call the function stored in `boxed_closure`, surround the field access with parentheses
4247
|
43-
= help: use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field
48+
LL | (boxed_fn.boxed_closure)();
49+
| ^ ^
4450

4551
error[E0599]: no method named `boxed_closure` found for type `BoxedObj` in the current scope
4652
--> $DIR/issue-2392.rs:52:19
@@ -50,8 +56,10 @@ LL | struct BoxedObj {
5056
...
5157
LL | boxed_closure.boxed_closure();
5258
| ^^^^^^^^^^^^^ field, not a method
59+
help: to call the function stored in `boxed_closure`, surround the field access with parentheses
5360
|
54-
= help: use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field
61+
LL | (boxed_closure.boxed_closure)();
62+
| ^ ^
5563

5664
error[E0599]: no method named `closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
5765
--> $DIR/issue-2392.rs:57:12
@@ -61,8 +69,10 @@ LL | struct Obj<F> where F: FnOnce() -> u32 {
6169
...
6270
LL | w.wrap.closure();
6371
| ^^^^^^^ field, not a method
72+
help: to call the function stored in `closure`, surround the field access with parentheses
6473
|
65-
= help: use `(w.wrap.closure)(...)` if you meant to call the function stored in the `closure` field
74+
LL | (w.wrap.closure)();
75+
| ^ ^
6676

6777
error[E0599]: no method named `not_closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
6878
--> $DIR/issue-2392.rs:59:12
@@ -71,9 +81,9 @@ LL | struct Obj<F> where F: FnOnce() -> u32 {
7181
| -------------------------------------- method `not_closure` not found for this
7282
...
7383
LL | w.wrap.not_closure();
74-
| ^^^^^^^^^^^ field, not a method
75-
|
76-
= help: did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`?
84+
| ^^^^^^^^^^^-- help: remove the arguments
85+
| |
86+
| field, not a method
7787

7888
error[E0599]: no method named `closure` found for type `Obj<std::boxed::Box<(dyn std::boxed::FnBox<(), Output=u32> + 'static)>>` in the current scope
7989
--> $DIR/issue-2392.rs:62:24
@@ -83,8 +93,10 @@ LL | struct Obj<F> where F: FnOnce() -> u32 {
8393
...
8494
LL | check_expression().closure();
8595
| ^^^^^^^ field, not a method
96+
help: to call the function stored in `closure`, surround the field access with parentheses
8697
|
87-
= help: use `(check_expression().closure)(...)` if you meant to call the function stored in the `closure` field
98+
LL | (check_expression().closure)();
99+
| ^ ^
88100

89101
error[E0599]: no method named `f1` found for type `FuncContainer` in the current scope
90102
--> $DIR/issue-2392.rs:68:31
@@ -94,8 +106,10 @@ LL | struct FuncContainer {
94106
...
95107
LL | (*self.container).f1(1);
96108
| ^^ field, not a method
109+
help: to call the function stored in `f1`, surround the field access with parentheses
97110
|
98-
= help: use `((*self.container).f1)(...)` if you meant to call the function stored in the `f1` field
111+
LL | ((*self.container).f1)(1);
112+
| ^ ^
99113

100114
error[E0599]: no method named `f2` found for type `FuncContainer` in the current scope
101115
--> $DIR/issue-2392.rs:69:31
@@ -105,8 +119,10 @@ LL | struct FuncContainer {
105119
...
106120
LL | (*self.container).f2(1);
107121
| ^^ field, not a method
122+
help: to call the function stored in `f2`, surround the field access with parentheses
108123
|
109-
= help: use `((*self.container).f2)(...)` if you meant to call the function stored in the `f2` field
124+
LL | ((*self.container).f2)(1);
125+
| ^ ^
110126

111127
error[E0599]: no method named `f3` found for type `FuncContainer` in the current scope
112128
--> $DIR/issue-2392.rs:70:31
@@ -116,8 +132,10 @@ LL | struct FuncContainer {
116132
...
117133
LL | (*self.container).f3(1);
118134
| ^^ field, not a method
135+
help: to call the function stored in `f3`, surround the field access with parentheses
119136
|
120-
= help: use `((*self.container).f3)(...)` if you meant to call the function stored in the `f3` field
137+
LL | ((*self.container).f3)(1);
138+
| ^ ^
121139

122140
error: aborting due to 11 previous errors
123141

src/test/ui/confuse-field-and-method/issue-32128.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ LL | struct Example {
66
...
77
LL | demo.example(1);
88
| ^^^^^^^ field, not a method
9+
help: to call the function stored in `example`, surround the field access with parentheses
910
|
10-
= help: use `(demo.example)(...)` if you meant to call the function stored in the `example` field
11+
LL | (demo.example)(1);
12+
| ^ ^
1113

1214
error: aborting due to previous error
1315

src/test/ui/confuse-field-and-method/issue-33784.stderr

+9-3
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,30 @@ error[E0599]: no method named `closure` found for type `&Obj<[closure@$DIR/issue
33
|
44
LL | p.closure();
55
| ^^^^^^^ field, not a method
6+
help: to call the function stored in `closure`, surround the field access with parentheses
67
|
7-
= help: use `(p.closure)(...)` if you meant to call the function stored in the `closure` field
8+
LL | (p.closure)();
9+
| ^ ^
810

911
error[E0599]: no method named `fn_ptr` found for type `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope
1012
--> $DIR/issue-33784.rs:29:7
1113
|
1214
LL | q.fn_ptr();
1315
| ^^^^^^ field, not a method
16+
help: to call the function stored in `fn_ptr`, surround the field access with parentheses
1417
|
15-
= help: use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field
18+
LL | (q.fn_ptr)();
19+
| ^ ^
1620

1721
error[E0599]: no method named `c_fn_ptr` found for type `&D` in the current scope
1822
--> $DIR/issue-33784.rs:32:7
1923
|
2024
LL | s.c_fn_ptr();
2125
| ^^^^^^^^ field, not a method
26+
help: to call the function stored in `c_fn_ptr`, surround the field access with parentheses
2227
|
23-
= help: use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` field
28+
LL | (s.c_fn_ptr)();
29+
| ^ ^
2430

2531
error: aborting due to 3 previous errors
2632

0 commit comments

Comments
 (0)