Skip to content

Commit 9577734

Browse files
authored
Rollup merge of rust-lang#55862 - zackmdavis:but_will_they_come_when_you_call_them, r=estebank
in which the E0618 "expected function" diagnostic gets a makeover A woman of wisdom once told me, "Better late than never." (Can't reopen the previously-closed pull request from six months ago [due to GitHub limitations](rust-lang#51098 (comment)).) 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). ![not_a_fn_1](https://user-images.githubusercontent.com/1076988/48309935-96755000-e538-11e8-9390-02a048abb0c2.png) ![not_a_fn_2](https://user-images.githubusercontent.com/1076988/48309936-98d7aa00-e538-11e8-8b9b-257bc77d6261.png) 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 rust-lang#51055. r? @estebank
2 parents 7130947 + f3e9b1a commit 9577734

18 files changed

+160
-60
lines changed

src/librustc_typeck/check/callee.rs

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -219,35 +219,62 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
219219
}
220220
}
221221

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

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

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

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

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

Lines changed: 10 additions & 2 deletions
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

Lines changed: 12 additions & 4 deletions
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

Lines changed: 6 additions & 2 deletions
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

Lines changed: 6 additions & 2 deletions
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

Lines changed: 3 additions & 1 deletion
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

Lines changed: 3 additions & 1 deletion
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

Lines changed: 6 additions & 2 deletions
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

Lines changed: 3 additions & 1 deletion
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

Lines changed: 1 addition & 2 deletions
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 3 additions & 1 deletion
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

Lines changed: 3 additions & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 3 additions & 1 deletion
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

Lines changed: 9 additions & 3 deletions
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;
Lines changed: 8 additions & 0 deletions
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)