From a449bdb20e5fd691f6d2445a6a58f5a089d60dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 12 Sep 2016 22:11:05 -0700 Subject: [PATCH] Reword error when data-less enum variant called as function Given a file like: ```rust enum Test { Variant, Variant2 {a: u32}, } fn main(){ let x = Test::Variant("Hello"); let y = Test::Variant2("World"); } ``` The errors now look this way: ```bash error[E0423]: `Test::Variant2` is the name of a struct or struct variant, but this expression uses it like a function name --> file3.rs:10:13 | 10 | let y = Test::Variant2("Hello"); | ^^^^^^^^^^^^^^ struct called like a function | = help: did you mean to write: `Test::Variant2 { /* fields */ }`? error: `Test::Variant` is being called, but it is not a function --> file3.rs:9:13 | 9 | let x = Test::Variant("World"); | ^^^^^^^^^^^^^^^^^^^^^^ | = help: did you mean to write: `Test::Variant`? note: defined here --> file3.rs:2:5 | 2 | Variant, | ^^^^^^^ error: aborting due to previous error ``` --- src/librustc_typeck/check/callee.rs | 32 +++++++++++++------ .../compile-fail/empty-struct-unit-expr.rs | 8 +++-- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index c5a21d7dd91ce..ac67f75743e84 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -13,6 +13,7 @@ use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag}; use CrateCtxt; use hir::def::Def; use hir::def_id::{DefId, LOCAL_CRATE}; +use hir::print; use rustc::{infer, traits}; use rustc::ty::{self, LvaluePreference, Ty}; use syntax::parse::token; @@ -194,15 +195,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let error_fn_sig; let fn_sig = match callee_ty.sty { - ty::TyFnDef(.., &ty::BareFnTy { ref sig, .. }) | - ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => sig, - _ => { - let mut err = self.type_error_struct(call_expr.span, - |actual| { - format!("expected function, found `{}`", - actual) - }, - callee_ty); + ty::TyFnDef(.., &ty::BareFnTy {ref sig, ..}) | + ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => sig, + ref t => { + let mut unit_variant = None; + if let &ty::TyAdt(adt_def, ..) = t { + if adt_def.is_enum() { + if let hir::ExprCall(ref expr, _) = call_expr.node { + unit_variant = Some(print::expr_to_string(expr)) + } + } + } + let mut err = if let Some(path) = unit_variant { + let mut err = self.type_error_struct(call_expr.span, |_| { + format!("`{}` is being called, but it is not a function", path) + }, callee_ty); + err.help(&format!("did you mean to write `{}`?", path)); + err + } else { + self.type_error_struct(call_expr.span, |actual| { + format!("expected function, found `{}`", actual) + }, callee_ty) + }; if let hir::ExprCall(ref expr, _) = call_expr.node { let tcx = self.tcx; diff --git a/src/test/compile-fail/empty-struct-unit-expr.rs b/src/test/compile-fail/empty-struct-unit-expr.rs index 350b96c764ca6..273ce91a7c5b8 100644 --- a/src/test/compile-fail/empty-struct-unit-expr.rs +++ b/src/test/compile-fail/empty-struct-unit-expr.rs @@ -23,7 +23,11 @@ enum E { fn main() { let e2 = Empty2(); //~ ERROR expected function, found `Empty2` - let e4 = E::Empty4(); //~ ERROR expected function, found `E` + let e4 = E::Empty4(); + //~^ ERROR `E::Empty4` is being called, but it is not a function + //~| HELP did you mean to write `E::Empty4`? let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2` - let xe4 = XE::XEmpty4(); //~ ERROR expected function, found `empty_struct::XE` + let xe4 = XE::XEmpty4(); + //~^ ERROR `XE::XEmpty4` is being called, but it is not a function + //~| HELP did you mean to write `XE::XEmpty4`? }