Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

in which the E0618 "expected function" diagnostic gets a makeover #55862

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 63 additions & 32 deletions src/librustc_typeck/check/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,35 +218,62 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}

let mut err = type_error_struct!(
self.tcx.sess,
call_expr.span,
callee_ty,
E0618,
"expected function, found {}",
match unit_variant {
Some(ref path) => format!("enum variant `{}`", path),
None => format!("`{}`", callee_ty),
});

err.span_label(call_expr.span, "not a function");
if let hir::ExprKind::Call(ref callee, _) = call_expr.node {
let mut err = type_error_struct!(
self.tcx.sess,
callee.span,
callee_ty,
E0618,
"expected function, found {}",
match unit_variant {
Some(ref path) => format!("enum variant `{}`", path),
None => format!("`{}`", callee_ty),
});

if let Some(ref path) = unit_variant {
err.span_suggestion_with_applicability(
call_expr.span,
&format!("`{}` is a unit variant, you need to write it \
without the parenthesis", path),
path.to_string(),
Applicability::MachineApplicable
);
}
if let Some(ref path) = unit_variant {
err.span_suggestion_with_applicability(
call_expr.span,
&format!("`{}` is a unit variant, you need to write it \
without the parenthesis", path),
path.to_string(),
Applicability::MachineApplicable
);
}

if let hir::ExprKind::Call(ref expr, _) = call_expr.node {
let def = if let hir::ExprKind::Path(ref qpath) = expr.node {
self.tables.borrow().qpath_def(qpath, expr.hir_id)
} else {
Def::Err
let mut inner_callee_path = None;
let def = match callee.node {
hir::ExprKind::Path(ref qpath) => {
self.tables.borrow().qpath_def(qpath, callee.hir_id)
},
hir::ExprKind::Call(ref inner_callee, _) => {
// If the call spans more than one line and the callee kind is
// itself another `ExprCall`, that's a clue that we might just be
// missing a semicolon (Issue #51055)
let call_is_multiline = self.tcx.sess.source_map()
.is_multiline(call_expr.span);
if call_is_multiline {
let span = self.tcx.sess.source_map().next_point(callee.span);
err.span_suggestion_with_applicability(
span,
"try adding a semicolon",
";".to_owned(),
Applicability::MaybeIncorrect
);
}
if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.node {
inner_callee_path = Some(inner_qpath);
self.tables.borrow().qpath_def(inner_qpath, inner_callee.hir_id)
} else {
Def::Err
}
},
_ => {
Def::Err
}
};

err.span_label(call_expr.span, "call expression requires function");

let def_span = match def {
Def::Err => None,
Def::Local(id) | Def::Upvar(id, ..) => {
Expand All @@ -255,16 +282,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => self.tcx.hir.span_if_local(def.def_id())
};
if let Some(span) = def_span {
let name = match unit_variant {
Some(path) => path,
None => callee_ty.to_string(),
let label = match (unit_variant, inner_callee_path) {
(Some(path), _) => format!("`{}` defined here", path),
(_, Some(hir::QPath::Resolved(_, path))) => format!(
"`{}` defined here returns `{}`", path, callee_ty.to_string()
),
_ => format!("`{}` defined here", callee_ty.to_string()),
};
err.span_label(span, format!("`{}` defined here", name));
err.span_label(span, label);
}
err.emit();
} else {
bug!("call_expr.node should be an ExprKind::Call, got {:?}", call_expr.node);
}

err.emit();

// This is the "default" function signature, used in case of error.
// In that case, we check each argument against "error" in order to
// set up all the node type bindings.
Expand Down
12 changes: 10 additions & 2 deletions src/test/ui/block-result/issue-20862.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,16 @@ LL | |y| x + y
error[E0618]: expected function, found `()`
--> $DIR/issue-20862.rs:17:13
|
LL | let x = foo(5)(2);
| ^^^^^^^^^ not a function
LL | / fn foo(x: i32) {
LL | | |y| x + y
LL | | //~^ ERROR: mismatched types
LL | | }
| |_- `foo` defined here returns `()`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

...
LL | let x = foo(5)(2);
| ^^^^^^---
| |
| call expression requires function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder how muddled it'd be if you kept the "not a function" label pointing at the primary span. Even better, detecting chained calls would be nice to provide a custom message (follow up work that needs more thought put into it):

error[E0618]: expected function, found `()`
  --> $DIR/issue-20862.rs:17:13
   |
LL | / fn foo(x: i32) {
LL | |     |y| x + y
LL | | //~^ ERROR: mismatched types
LL | | }
   | |_- `foo` defined here returns `()`
...
LL |       let x = foo(5)(2);
   |               ^^^^^^---
   |               |
   |               call expression requires function
  = note: the highlighted code below resolves to `()`...
LL |       let x = foo(5)(2);
   |               ^^^^^^
  = note: ...which cannot be called with the arguments `(2)`


error: aborting due to 2 previous errors

Expand Down
16 changes: 12 additions & 4 deletions src/test/ui/empty/empty-struct-unit-expr.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ LL | struct Empty2;
| -------------- `Empty2` defined here
...
LL | let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
| ^^^^^^^^ not a function
| ^^^^^^--
| |
| call expression requires function

error[E0618]: expected function, found enum variant `E::Empty4`
--> $DIR/empty-struct-unit-expr.rs:26:14
Expand All @@ -14,7 +16,9 @@ LL | Empty4
| ------ `E::Empty4` defined here
...
LL | let e4 = E::Empty4();
| ^^^^^^^^^^^ not a function
| ^^^^^^^^^--
| |
| call expression requires function
help: `E::Empty4` is a unit variant, you need to write it without the parenthesis
|
LL | let e4 = E::Empty4;
Expand All @@ -24,13 +28,17 @@ error[E0618]: expected function, found `empty_struct::XEmpty2`
--> $DIR/empty-struct-unit-expr.rs:28:15
|
LL | let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2`
| ^^^^^^^^^ not a function
| ^^^^^^^--
| |
| call expression requires function

error[E0618]: expected function, found enum variant `XE::XEmpty4`
--> $DIR/empty-struct-unit-expr.rs:29:15
|
LL | let xe4 = XE::XEmpty4();
| ^^^^^^^^^^^^^ not a function
| ^^^^^^^^^^^--
| |
| call expression requires function
help: `XE::XEmpty4` is a unit variant, you need to write it without the parenthesis
|
LL | let xe4 = XE::XEmpty4;
Expand Down
8 changes: 6 additions & 2 deletions src/test/ui/error-codes/E0618.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ LL | Entry,
| ----- `X::Entry` defined here
...
LL | X::Entry();
| ^^^^^^^^^^ not a function
| ^^^^^^^^--
| |
| call expression requires function
help: `X::Entry` is a unit variant, you need to write it without the parenthesis
|
LL | X::Entry;
Expand All @@ -17,7 +19,9 @@ error[E0618]: expected function, found `i32`
LL | let x = 0i32;
| - `i32` defined here
LL | x();
| ^^^ not a function
| ^--
| |
| call expression requires function

error: aborting due to 2 previous errors

Expand Down
8 changes: 6 additions & 2 deletions src/test/ui/issues/issue-10969.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@ error[E0618]: expected function, found `i32`
LL | fn func(i: i32) {
| - `i32` defined here
LL | i(); //~ERROR expected function, found `i32`
| ^^^ not a function
| ^--
| |
| call expression requires function

error[E0618]: expected function, found `i32`
--> $DIR/issue-10969.rs:16:5
|
LL | let i = 0i32;
| - `i32` defined here
LL | i(); //~ERROR expected function, found `i32`
| ^^^ not a function
| ^--
| |
| call expression requires function

error: aborting due to 2 previous errors

Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/issues/issue-18532.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ error[E0618]: expected function, found `!`
--> $DIR/issue-18532.rs:16:5
|
LL | (return)((),()); //~ ERROR expected function, found `!`
| ^^^^^^^^^^^^^^^ not a function
| ^^^^^^^^-------
| |
| call expression requires function

error: aborting due to previous error

Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/issues/issue-20714.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ LL | struct G;
| --------- `G` defined here
...
LL | let g = G(); //~ ERROR: expected function, found `G`
| ^^^ not a function
| ^--
| |
| call expression requires function

error: aborting due to previous error

Expand Down
8 changes: 6 additions & 2 deletions src/test/ui/issues/issue-21701.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ error[E0618]: expected function, found `U`
LL | fn foo<U>(t: U) {
| - `U` defined here
LL | let y = t();
| ^^^ not a function
| ^--
| |
| call expression requires function

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

error: aborting due to 2 previous errors

Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/issues/issue-22468.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ error[E0618]: expected function, found `&str`
LL | let foo = "bar";
| --- `&str` defined here
LL | let x = foo("baz");
| ^^^^^^^^^^ not a function
| ^^^-------
| |
| call expression requires function

error: aborting due to previous error

Expand Down
3 changes: 1 addition & 2 deletions src/test/ui/issues/issue-26237.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@
macro_rules! macro_panic {
($not_a_function:expr, $some_argument:ident) => {
$not_a_function($some_argument)
//~^ ERROR expected function, found `{integer}`
}
}

fn main() {
let mut value_a = 0;
let mut value_b = 0;
macro_panic!(value_a, value_b);
//~^ in this expansion of macro_panic!
//~^ ERROR expected function, found `{integer}`
}
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-26237.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
error[E0618]: expected function, found `{integer}`
--> $DIR/issue-26237.rs:13:9
--> $DIR/issue-26237.rs:20:18
|
LL | $not_a_function($some_argument)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a function
| ------------------------------- call expression requires function
...
LL | let mut value_a = 0;
| ----------- `{integer}` defined here
LL | let mut value_b = 0;
LL | macro_panic!(value_a, value_b);
| ------------------------------- in this macro invocation
| ^^^^^^^

error: aborting due to previous error

Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/issues/issue-45965.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ error[E0618]: expected function, found `{float}`
--> $DIR/issue-45965.rs:12:30
|
LL | let a = |r: f64| if r != 0.0(r != 0.0) { 1.0 } else { 0.0 };
| ^^^^^^^^^^^^^ not a function
| ^^^----------
| |
| call expression requires function

error: aborting due to previous error

Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/issues/issue-46771.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ error[E0618]: expected function, found `main::Foo`
LL | struct Foo;
| ----------- `main::Foo` defined here
LL | (1 .. 2).find(|_| Foo(0) == 0); //~ ERROR expected function, found `main::Foo`
| ^^^^^^ not a function
| ^^^---
| |
| call expression requires function

error: aborting due to previous error

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-5100.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ error[E0618]: expected function, found `(char, char)`
--> $DIR/issue-5100.rs:58:14
|
LL | let v = [('a', 'b') //~ ERROR expected function, found `(char, char)`
| ______________^
| ______________-^^^^^^^^^
LL | | ('c', 'd'),
| |_______________________^ not a function
| |_______________________- call expression requires function

error[E0308]: mismatched types
--> $DIR/issue-5100.rs:65:19
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/parse-error-correct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ LL | let y = 42;
| - `{integer}` defined here
LL | let x = y.; //~ ERROR unexpected token
LL | let x = y.(); //~ ERROR unexpected token
| ^^^^ not a function
| ^---
| |
| call expression requires function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised at the parser taking this as a function call (but it's not problematic).


error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
--> $DIR/parse-error-correct.rs:21:15
Expand Down
12 changes: 9 additions & 3 deletions src/test/ui/resolve/privacy-enum-ctor.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ LL | Unit,
| ---- `Z::Unit` defined here
...
LL | let _ = Z::Unit();
| ^^^^^^^^^ not a function
| ^^^^^^^--
| |
| call expression requires function
help: `Z::Unit` is a unit variant, you need to write it without the parenthesis
|
LL | let _ = Z::Unit;
Expand All @@ -193,7 +195,9 @@ LL | Unit,
| ---- `m::E::Unit` defined here
...
LL | let _: E = m::E::Unit();
| ^^^^^^^^^^^^ not a function
| ^^^^^^^^^^--
| |
| call expression requires function
help: `m::E::Unit` is a unit variant, you need to write it without the parenthesis
|
LL | let _: E = m::E::Unit;
Expand All @@ -215,7 +219,9 @@ LL | Unit,
| ---- `E::Unit` defined here
...
LL | let _: E = E::Unit();
| ^^^^^^^^^ not a function
| ^^^^^^^--
| |
| call expression requires function
help: `E::Unit` is a unit variant, you need to write it without the parenthesis
|
LL | let _: E = E::Unit;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fn vindictive() -> bool { true }

fn perfidy() -> (i32, i32) {
vindictive() //~ ERROR expected function, found `bool`
(1, 2)
}

fn main() {}
Loading