Skip to content

Commit f3e9b1a

Browse files
committed
in which the E0618 "expected function" diagnostic gets a makeover
Now the main span focuses on the erroneous not-a-function callee, while showing the entire call expression is relegated to a secondary span. In the case where the erroneous callee is itself a call, we point out the definition, and, if the call expression spans multiple lines, tentatively suggest a semicolon (because we suspect that the "outer" call is actually supposed to be a tuple). The new `bug!` assertion is, in fact, safe (`confirm_builtin_call` is only called by `check_call`, which is only called with a first arg of kind `ExprKind::Call` in `check_expr_kind`). Resolves #51055.
1 parent 6408162 commit f3e9b1a

18 files changed

+160
-60
lines changed

src/librustc_typeck/check/callee.rs

+63-32
Original file line numberDiff line numberDiff line change
@@ -218,35 +218,62 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
218218
}
219219
}
220220

221-
let mut err = type_error_struct!(
222-
self.tcx.sess,
223-
call_expr.span,
224-
callee_ty,
225-
E0618,
226-
"expected function, found {}",
227-
match unit_variant {
228-
Some(ref path) => format!("enum variant `{}`", path),
229-
None => format!("`{}`", callee_ty),
230-
});
231-
232-
err.span_label(call_expr.span, "not a function");
221+
if let hir::ExprKind::Call(ref callee, _) = call_expr.node {
222+
let mut err = type_error_struct!(
223+
self.tcx.sess,
224+
callee.span,
225+
callee_ty,
226+
E0618,
227+
"expected function, found {}",
228+
match unit_variant {
229+
Some(ref path) => format!("enum variant `{}`", path),
230+
None => format!("`{}`", callee_ty),
231+
});
233232

234-
if let Some(ref path) = unit_variant {
235-
err.span_suggestion_with_applicability(
236-
call_expr.span,
237-
&format!("`{}` is a unit variant, you need to write it \
238-
without the parenthesis", path),
239-
path.to_string(),
240-
Applicability::MachineApplicable
241-
);
242-
}
233+
if let Some(ref path) = unit_variant {
234+
err.span_suggestion_with_applicability(
235+
call_expr.span,
236+
&format!("`{}` is a unit variant, you need to write it \
237+
without the parenthesis", path),
238+
path.to_string(),
239+
Applicability::MachineApplicable
240+
);
241+
}
243242

244-
if let hir::ExprKind::Call(ref expr, _) = call_expr.node {
245-
let def = if let hir::ExprKind::Path(ref qpath) = expr.node {
246-
self.tables.borrow().qpath_def(qpath, expr.hir_id)
247-
} else {
248-
Def::Err
243+
let mut inner_callee_path = None;
244+
let def = match callee.node {
245+
hir::ExprKind::Path(ref qpath) => {
246+
self.tables.borrow().qpath_def(qpath, callee.hir_id)
247+
},
248+
hir::ExprKind::Call(ref inner_callee, _) => {
249+
// If the call spans more than one line and the callee kind is
250+
// itself another `ExprCall`, that's a clue that we might just be
251+
// missing a semicolon (Issue #51055)
252+
let call_is_multiline = self.tcx.sess.source_map()
253+
.is_multiline(call_expr.span);
254+
if call_is_multiline {
255+
let span = self.tcx.sess.source_map().next_point(callee.span);
256+
err.span_suggestion_with_applicability(
257+
span,
258+
"try adding a semicolon",
259+
";".to_owned(),
260+
Applicability::MaybeIncorrect
261+
);
262+
}
263+
if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.node {
264+
inner_callee_path = Some(inner_qpath);
265+
self.tables.borrow().qpath_def(inner_qpath, inner_callee.hir_id)
266+
} else {
267+
Def::Err
268+
}
269+
},
270+
_ => {
271+
Def::Err
272+
}
249273
};
274+
275+
err.span_label(call_expr.span, "call expression requires function");
276+
250277
let def_span = match def {
251278
Def::Err => None,
252279
Def::Local(id) | Def::Upvar(id, ..) => {
@@ -255,16 +282,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
255282
_ => self.tcx.hir.span_if_local(def.def_id())
256283
};
257284
if let Some(span) = def_span {
258-
let name = match unit_variant {
259-
Some(path) => path,
260-
None => callee_ty.to_string(),
285+
let label = match (unit_variant, inner_callee_path) {
286+
(Some(path), _) => format!("`{}` defined here", path),
287+
(_, Some(hir::QPath::Resolved(_, path))) => format!(
288+
"`{}` defined here returns `{}`", path, callee_ty.to_string()
289+
),
290+
_ => format!("`{}` defined here", callee_ty.to_string()),
261291
};
262-
err.span_label(span, format!("`{}` defined here", name));
292+
err.span_label(span, label);
263293
}
294+
err.emit();
295+
} else {
296+
bug!("call_expr.node should be an ExprKind::Call, got {:?}", call_expr.node);
264297
}
265298

266-
err.emit();
267-
268299
// This is the "default" function signature, used in case of error.
269300
// In that case, we check each argument against "error" in order to
270301
// set up all the node type bindings.

src/test/ui/block-result/issue-20862.stderr

+10-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,16 @@ LL | |y| x + y
1212
error[E0618]: expected function, found `()`
1313
--> $DIR/issue-20862.rs:17:13
1414
|
15-
LL | let x = foo(5)(2);
16-
| ^^^^^^^^^ not a function
15+
LL | / fn foo(x: i32) {
16+
LL | | |y| x + y
17+
LL | | //~^ ERROR: mismatched types
18+
LL | | }
19+
| |_- `foo` defined here returns `()`
20+
...
21+
LL | let x = foo(5)(2);
22+
| ^^^^^^---
23+
| |
24+
| call expression requires function
1725

1826
error: aborting due to 2 previous errors
1927

src/test/ui/empty/empty-struct-unit-expr.stderr

+12-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ LL | struct Empty2;
55
| -------------- `Empty2` defined here
66
...
77
LL | let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
8-
| ^^^^^^^^ not a function
8+
| ^^^^^^--
9+
| |
10+
| call expression requires function
911

1012
error[E0618]: expected function, found enum variant `E::Empty4`
1113
--> $DIR/empty-struct-unit-expr.rs:26:14
@@ -14,7 +16,9 @@ LL | Empty4
1416
| ------ `E::Empty4` defined here
1517
...
1618
LL | let e4 = E::Empty4();
17-
| ^^^^^^^^^^^ not a function
19+
| ^^^^^^^^^--
20+
| |
21+
| call expression requires function
1822
help: `E::Empty4` is a unit variant, you need to write it without the parenthesis
1923
|
2024
LL | let e4 = E::Empty4;
@@ -24,13 +28,17 @@ error[E0618]: expected function, found `empty_struct::XEmpty2`
2428
--> $DIR/empty-struct-unit-expr.rs:28:15
2529
|
2630
LL | let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2`
27-
| ^^^^^^^^^ not a function
31+
| ^^^^^^^--
32+
| |
33+
| call expression requires function
2834

2935
error[E0618]: expected function, found enum variant `XE::XEmpty4`
3036
--> $DIR/empty-struct-unit-expr.rs:29:15
3137
|
3238
LL | let xe4 = XE::XEmpty4();
33-
| ^^^^^^^^^^^^^ not a function
39+
| ^^^^^^^^^^^--
40+
| |
41+
| call expression requires function
3442
help: `XE::XEmpty4` is a unit variant, you need to write it without the parenthesis
3543
|
3644
LL | let xe4 = XE::XEmpty4;

src/test/ui/error-codes/E0618.stderr

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ LL | Entry,
55
| ----- `X::Entry` defined here
66
...
77
LL | X::Entry();
8-
| ^^^^^^^^^^ not a function
8+
| ^^^^^^^^--
9+
| |
10+
| call expression requires function
911
help: `X::Entry` is a unit variant, you need to write it without the parenthesis
1012
|
1113
LL | X::Entry;
@@ -17,7 +19,9 @@ error[E0618]: expected function, found `i32`
1719
LL | let x = 0i32;
1820
| - `i32` defined here
1921
LL | x();
20-
| ^^^ not a function
22+
| ^--
23+
| |
24+
| call expression requires function
2125

2226
error: aborting due to 2 previous errors
2327

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@ error[E0618]: expected function, found `i32`
44
LL | fn func(i: i32) {
55
| - `i32` defined here
66
LL | i(); //~ERROR expected function, found `i32`
7-
| ^^^ not a function
7+
| ^--
8+
| |
9+
| call expression requires function
810

911
error[E0618]: expected function, found `i32`
1012
--> $DIR/issue-10969.rs:16:5
1113
|
1214
LL | let i = 0i32;
1315
| - `i32` defined here
1416
LL | i(); //~ERROR expected function, found `i32`
15-
| ^^^ not a function
17+
| ^--
18+
| |
19+
| call expression requires function
1620

1721
error: aborting due to 2 previous errors
1822

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0618]: expected function, found `!`
22
--> $DIR/issue-18532.rs:16:5
33
|
44
LL | (return)((),()); //~ ERROR expected function, found `!`
5-
| ^^^^^^^^^^^^^^^ not a function
5+
| ^^^^^^^^-------
6+
| |
7+
| call expression requires function
68

79
error: aborting due to previous error
810

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ LL | struct G;
55
| --------- `G` defined here
66
...
77
LL | let g = G(); //~ ERROR: expected function, found `G`
8-
| ^^^ not a function
8+
| ^--
9+
| |
10+
| call expression requires function
911

1012
error: aborting due to previous error
1113

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ error[E0618]: expected function, found `U`
44
LL | fn foo<U>(t: U) {
55
| - `U` defined here
66
LL | let y = t();
7-
| ^^^ not a function
7+
| ^--
8+
| |
9+
| call expression requires function
810

911
error[E0618]: expected function, found `Bar`
1012
--> $DIR/issue-21701.rs:19:13
@@ -13,7 +15,9 @@ LL | struct Bar;
1315
| ----------- `Bar` defined here
1416
...
1517
LL | let f = Bar();
16-
| ^^^^^ not a function
18+
| ^^^--
19+
| |
20+
| call expression requires function
1721

1822
error: aborting due to 2 previous errors
1923

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ error[E0618]: expected function, found `&str`
44
LL | let foo = "bar";
55
| --- `&str` defined here
66
LL | let x = foo("baz");
7-
| ^^^^^^^^^^ not a function
7+
| ^^^-------
8+
| |
9+
| call expression requires function
810

911
error: aborting due to previous error
1012

src/test/ui/issues/issue-26237.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@
1111
macro_rules! macro_panic {
1212
($not_a_function:expr, $some_argument:ident) => {
1313
$not_a_function($some_argument)
14-
//~^ ERROR expected function, found `{integer}`
1514
}
1615
}
1716

1817
fn main() {
1918
let mut value_a = 0;
2019
let mut value_b = 0;
2120
macro_panic!(value_a, value_b);
22-
//~^ in this expansion of macro_panic!
21+
//~^ ERROR expected function, found `{integer}`
2322
}

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
error[E0618]: expected function, found `{integer}`
2-
--> $DIR/issue-26237.rs:13:9
2+
--> $DIR/issue-26237.rs:20:18
33
|
44
LL | $not_a_function($some_argument)
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a function
5+
| ------------------------------- call expression requires function
66
...
77
LL | let mut value_a = 0;
88
| ----------- `{integer}` defined here
99
LL | let mut value_b = 0;
1010
LL | macro_panic!(value_a, value_b);
11-
| ------------------------------- in this macro invocation
11+
| ^^^^^^^
1212

1313
error: aborting due to previous error
1414

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0618]: expected function, found `{float}`
22
--> $DIR/issue-45965.rs:12:30
33
|
44
LL | let a = |r: f64| if r != 0.0(r != 0.0) { 1.0 } else { 0.0 };
5-
| ^^^^^^^^^^^^^ not a function
5+
| ^^^----------
6+
| |
7+
| call expression requires function
68

79
error: aborting due to previous error
810

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ error[E0618]: expected function, found `main::Foo`
44
LL | struct Foo;
55
| ----------- `main::Foo` defined here
66
LL | (1 .. 2).find(|_| Foo(0) == 0); //~ ERROR expected function, found `main::Foo`
7-
| ^^^^^^ not a function
7+
| ^^^---
8+
| |
9+
| call expression requires function
810

911
error: aborting due to previous error
1012

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ error[E0618]: expected function, found `(char, char)`
4747
--> $DIR/issue-5100.rs:58:14
4848
|
4949
LL | let v = [('a', 'b') //~ ERROR expected function, found `(char, char)`
50-
| ______________^
50+
| ______________-^^^^^^^^^
5151
LL | | ('c', 'd'),
52-
| |_______________________^ not a function
52+
| |_______________________- call expression requires function
5353

5454
error[E0308]: mismatched types
5555
--> $DIR/issue-5100.rs:65:19

src/test/ui/parse-error-correct.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ LL | let y = 42;
1717
| - `{integer}` defined here
1818
LL | let x = y.; //~ ERROR unexpected token
1919
LL | let x = y.(); //~ ERROR unexpected token
20-
| ^^^^ not a function
20+
| ^---
21+
| |
22+
| call expression requires function
2123

2224
error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
2325
--> $DIR/parse-error-correct.rs:21:15

src/test/ui/resolve/privacy-enum-ctor.stderr

+9-3
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ LL | Unit,
171171
| ---- `Z::Unit` defined here
172172
...
173173
LL | let _ = Z::Unit();
174-
| ^^^^^^^^^ not a function
174+
| ^^^^^^^--
175+
| |
176+
| call expression requires function
175177
help: `Z::Unit` is a unit variant, you need to write it without the parenthesis
176178
|
177179
LL | let _ = Z::Unit;
@@ -193,7 +195,9 @@ LL | Unit,
193195
| ---- `m::E::Unit` defined here
194196
...
195197
LL | let _: E = m::E::Unit();
196-
| ^^^^^^^^^^^^ not a function
198+
| ^^^^^^^^^^--
199+
| |
200+
| call expression requires function
197201
help: `m::E::Unit` is a unit variant, you need to write it without the parenthesis
198202
|
199203
LL | let _: E = m::E::Unit;
@@ -215,7 +219,9 @@ LL | Unit,
215219
| ---- `E::Unit` defined here
216220
...
217221
LL | let _: E = E::Unit();
218-
| ^^^^^^^^^ not a function
222+
| ^^^^^^^--
223+
| |
224+
| call expression requires function
219225
help: `E::Unit` is a unit variant, you need to write it without the parenthesis
220226
|
221227
LL | let _: E = E::Unit;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn vindictive() -> bool { true }
2+
3+
fn perfidy() -> (i32, i32) {
4+
vindictive() //~ ERROR expected function, found `bool`
5+
(1, 2)
6+
}
7+
8+
fn main() {}

0 commit comments

Comments
 (0)