]> git.lizzy.rs Git - rust.git/commitdiff
in which the E0618 "expected function" diagnostic gets a makeover
authorZack M. Davis <code@zackmdavis.net>
Sun, 11 Nov 2018 04:46:05 +0000 (20:46 -0800)
committerZack M. Davis <code@zackmdavis.net>
Sun, 11 Nov 2018 06:12:33 +0000 (22:12 -0800)
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.

18 files changed:
src/librustc_typeck/check/callee.rs
src/test/ui/block-result/issue-20862.stderr
src/test/ui/empty/empty-struct-unit-expr.stderr
src/test/ui/error-codes/E0618.stderr
src/test/ui/issues/issue-10969.stderr
src/test/ui/issues/issue-18532.stderr
src/test/ui/issues/issue-20714.stderr
src/test/ui/issues/issue-21701.stderr
src/test/ui/issues/issue-22468.stderr
src/test/ui/issues/issue-26237.rs
src/test/ui/issues/issue-26237.stderr
src/test/ui/issues/issue-45965.stderr
src/test/ui/issues/issue-46771.stderr
src/test/ui/issues/issue-5100.stderr
src/test/ui/parse-error-correct.stderr
src/test/ui/resolve/privacy-enum-ctor.stderr
src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr [new file with mode: 0644]

index de4293aaaeac79ef676869c4f1da015c0c8b291c..9b78351c3e1656653e35484aa7281763c0050bbc 100644 (file)
@@ -218,35 +218,62 @@ fn confirm_builtin_call(&self,
                     }
                 }
 
-                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, ..) => {
@@ -255,16 +282,20 @@ fn confirm_builtin_call(&self,
                         _ => 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.
index 990fb404c946669ee8f2dd80416e5627949a8a01..194cfab8527c014a2a08d212364d6449f92d670e 100644 (file)
@@ -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 `()`
+...
+LL |       let x = foo(5)(2);
+   |               ^^^^^^---
+   |               |
+   |               call expression requires function
 
 error: aborting due to 2 previous errors
 
index fff696fc80f058e01b30c55c9b75c99f006d9117..360e0c6f107b2cc991c91925e8eae502660fe9d0 100644 (file)
@@ -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
@@ -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;
@@ -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;
index ef7ace44d59a628afed5599471f75c88b79fe193..3bcc83e01c1f0f217c503630eca2cf59d6267f82 100644 (file)
@@ -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;
@@ -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
 
index edc4ecbab525a5f1954a6b746f744909815b835a..d04108ca39e24f782e0bfcef1920cd7830aff208 100644 (file)
@@ -4,7 +4,9 @@ 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
@@ -12,7 +14,9 @@ error[E0618]: expected function, found `i32`
 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
 
index 8f10cb0f7b03dbc1743a9e2300a6f1d6da1e7427..c297c20069ec235b09201f5d21f1c828a36f1819 100644 (file)
@@ -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
 
index 1ea85ee440e218bd1016664e3189e6048a7f4db8..70a9736d2a2433131fcef7537c9ad6c2ed09ea8f 100644 (file)
@@ -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
 
index 9fb9a7b51f280e3041f538d22cb63ad7533e893c..b94e0833a581072450ba76a828ac180c154ec8bc 100644 (file)
@@ -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
@@ -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
 
index 034a076fbfe836c415ec3ad0d3aeb6938b3d901d..af32c0e20ce9d5499c15724891c208ad9e652ab8 100644 (file)
@@ -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
 
index 22772e596b19ec19a68c607ef399bc903502504b..ffffe6d3ab5db93dfeaacdcf9faaa9bde1b153b4 100644 (file)
@@ -11,7 +11,6 @@
 macro_rules! macro_panic {
     ($not_a_function:expr, $some_argument:ident) => {
         $not_a_function($some_argument)
-        //~^ ERROR expected function, found `{integer}`
     }
 }
 
@@ -19,5 +18,5 @@ 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}`
 }
index ae6fda8b93248f36f03867a414a361506d343586..7f481c230ba65329f090b739ef517d7fbb7c7d12 100644 (file)
@@ -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
 
index 2b3870feef37ca644498b34c03b4cec9361fba2d..b7b5f76395a9dc4b3a4e94bd1ef28628b1da2025 100644 (file)
@@ -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
 
index 0d57d61e9ffe6b912a2facfde0bc62f938c567d2..90adb3ed73f5696beb8332306e8b25fc49a68834 100644 (file)
@@ -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
 
index 6f5a84966bf35e1865d16e08200b4e9f8937cd5d..305ee2f547145131cc913df95709f07beefaff16 100644 (file)
@@ -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
index 3eb0b19a6aaeab5bb8d886af67d034eab86e01cc..9c87806da9e5dd29c13411dd8dde22c2795236f0 100644 (file)
@@ -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
 
 error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
   --> $DIR/parse-error-correct.rs:21:15
index 8e08f124d6807f8fdfc9bf253cf346a128aac508..01e6488de5303ae387ae768a04f3bfb3edebcce7 100644 (file)
@@ -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;
@@ -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;
@@ -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;
diff --git a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs
new file mode 100644 (file)
index 0000000..37f0782
--- /dev/null
@@ -0,0 +1,8 @@
+fn vindictive() -> bool { true }
+
+fn perfidy() -> (i32, i32) {
+    vindictive() //~ ERROR expected function, found `bool`
+    (1, 2)
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr
new file mode 100644 (file)
index 0000000..40ddb5e
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0618]: expected function, found `bool`
+  --> $DIR/issue-51055-missing-semicolon-between-call-and-tuple.rs:4:5
+   |
+LL |   fn vindictive() -> bool { true }
+   |   -------------------------------- `vindictive` defined here returns `bool`
+...
+LL |       vindictive() //~ ERROR expected function, found `bool`
+   |       -^^^^^^^^^^^- help: try adding a semicolon: `;`
+   |  _____|
+   | |
+LL | |     (1, 2)
+   | |__________- call expression requires function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0618`.