From 195d837f18e2efb7d621d6568212a59c29fc184e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 8 Aug 2019 12:01:22 -0700 Subject: [PATCH] When suggesting fn call use an appropriate number of placeholder arguments --- src/librustc_typeck/check/mod.rs | 43 ++++++--- src/test/ui/issues/issue-35241.stderr | 2 +- src/test/ui/resolve/privacy-enum-ctor.stderr | 6 +- .../fn-or-tuple-struct-without-args.rs | 20 ++++ .../fn-or-tuple-struct-without-args.stderr | 93 +++++++++++++++++++ 5 files changed, 148 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs create mode 100644 src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6600f8339385..130cc8f3a605 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3833,19 +3833,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .0; let sig = self.normalize_associated_types_in(expr.span, &sig); if let Ok(_) = self.try_coerce(expr, sig.output(), expected, AllowTwoPhase::No) { - if let Ok(code) = self.sess().source_map().span_to_snippet(expr.span) { - err.span_suggestion(expr.span, "use parentheses to call this function", format!( - "{}({})", - code, - if sig.inputs().len() > 0 { - "..." - } else { - "" - }), if sig.inputs().len() > 0 { - Applicability::MachineApplicable - } else { - Applicability::HasPlaceholders + let (mut sugg_call, applicability) = if sig.inputs().is_empty() { + (String::new(), Applicability::MachineApplicable) + } else { + ("...".to_owned(), Applicability::HasPlaceholders) + }; + let mut msg = "call this function"; + if let ty::FnDef(def_id, ..) = found.sty { + match self.tcx.hir().get_if_local(def_id) { + Some(Node::Item(hir::Item { + node: ItemKind::Fn(.., body_id), + .. + })) => { + let body = self.tcx.hir().body(*body_id); + sugg_call = body.arguments.iter() + .map(|arg| hir::print::to_string( + hir::print::NO_ANN, + |s| s.print_pat(&arg.pat), + )).collect::>().join(", "); } + Some(Node::Ctor(hir::VariantData::Tuple(field, _))) => { + sugg_call = field.iter().map(|_| "_").collect::>().join(", "); + msg = "instatiate this tuple struct"; + } + _ => {} + } + }; + if let Ok(code) = self.sess().source_map().span_to_snippet(expr.span) { + err.span_suggestion( + expr.span, + &format!("use parentheses to {}", msg), + format!("{}({})", code, sugg_call), + applicability, ); return true; } diff --git a/src/test/ui/issues/issue-35241.stderr b/src/test/ui/issues/issue-35241.stderr index 248e6f0f46b1..8befc6873857 100644 --- a/src/test/ui/issues/issue-35241.stderr +++ b/src/test/ui/issues/issue-35241.stderr @@ -8,7 +8,7 @@ LL | fn test() -> Foo { Foo } | --- ^^^ | | | | | expected struct `Foo`, found fn item - | | help: use parentheses to call this function: `Foo(...)` + | | help: use parentheses to instatiate this tuple struct: `Foo(_)` | expected `Foo` because of return type | = note: expected type `Foo` diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 07cbffb00940..49092562feeb 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -202,7 +202,7 @@ LL | let _: Z = Z::Fn; | ^^^^^ | | | expected enum `m::n::Z`, found fn item - | help: use parentheses to call this function: `Z::Fn(...)` + | help: use parentheses to instatiate this tuple struct: `Z::Fn(_)` | = note: expected type `m::n::Z` found type `fn(u8) -> m::n::Z {m::n::Z::Fn}` @@ -232,7 +232,7 @@ LL | let _: E = m::E::Fn; | ^^^^^^^^ | | | expected enum `m::E`, found fn item - | help: use parentheses to call this function: `m::E::Fn(...)` + | help: use parentheses to instatiate this tuple struct: `m::E::Fn(_)` | = note: expected type `m::E` found type `fn(u8) -> m::E {m::E::Fn}` @@ -262,7 +262,7 @@ LL | let _: E = E::Fn; | ^^^^^ | | | expected enum `m::E`, found fn item - | help: use parentheses to call this function: `E::Fn(...)` + | help: use parentheses to instatiate this tuple struct: `E::Fn(_)` | = note: expected type `m::E` found type `fn(u8) -> m::E {m::E::Fn}` diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs new file mode 100644 index 000000000000..6758c1d5f238 --- /dev/null +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs @@ -0,0 +1,20 @@ +fn foo(a: usize, b: usize) -> usize { a } + +fn bar() -> usize { 42 } + +struct S(usize, usize); +struct V(); + +trait T { + fn baz(x: usize, y: usize) -> usize { x } + fn bat() -> usize { 42 } +} + +fn main() { + let _: usize = foo; //~ ERROR mismatched types + let _: S = S; //~ ERROR mismatched types + let _: usize = bar; //~ ERROR mismatched types + let _: V = V; //~ ERROR mismatched types + let _: usize = T::baz; //~ ERROR mismatched types + let _: usize = T::bat; //~ ERROR mismatched types +} diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr new file mode 100644 index 000000000000..524c779979e3 --- /dev/null +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -0,0 +1,93 @@ +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:14:20 + | +LL | fn foo(a: usize, b: usize) -> usize { a } + | ----------------------------------- fn(usize, usize) -> usize {foo} defined here +... +LL | let _: usize = foo; + | ^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `foo(a, b)` + | + = note: expected type `usize` + found type `fn(usize, usize) -> usize {foo}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:15:16 + | +LL | struct S(usize, usize); + | ----------------------- fn(usize, usize) -> S {S} defined here +... +LL | let _: S = S; + | ^ + | | + | expected struct `S`, found fn item + | help: use parentheses to instatiate this tuple struct: `S(_, _)` + | + = note: expected type `S` + found type `fn(usize, usize) -> S {S}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:16:20 + | +LL | fn bar() -> usize { 42 } + | ----------------- fn() -> usize {bar} defined here +... +LL | let _: usize = bar; + | ^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `bar()` + | + = note: expected type `usize` + found type `fn() -> usize {bar}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:17:16 + | +LL | struct V(); + | ----------- fn() -> V {V} defined here +... +LL | let _: V = V; + | ^ + | | + | expected struct `V`, found fn item + | help: use parentheses to instatiate this tuple struct: `V()` + | + = note: expected type `V` + found type `fn() -> V {V}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:18:20 + | +LL | fn baz(x: usize, y: usize) -> usize { x } + | ----------------------------------- fn(usize, usize) -> usize {<_ as T>::baz} defined here +... +LL | let _: usize = T::baz; + | ^^^^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `T::baz(...)` + | + = note: expected type `usize` + found type `fn(usize, usize) -> usize {<_ as T>::baz}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:19:20 + | +LL | fn bat() -> usize { 42 } + | ----------------- fn() -> usize {<_ as T>::bat} defined here +... +LL | let _: usize = T::bat; + | ^^^^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `T::bat()` + | + = note: expected type `usize` + found type `fn() -> usize {<_ as T>::bat}` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0308`.