From 15495767324ec173a01b6ff0197b5c4fceb61d21 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sat, 16 Apr 2022 15:38:32 -0400 Subject: [PATCH] Point at closure args too --- compiler/rustc_typeck/src/check/callee.rs | 11 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 122 +++++++----------- src/test/ui/argument-suggestions/basic.rs | 3 + src/test/ui/argument-suggestions/basic.stderr | 22 +++- src/test/ui/error-codes/E0057.stderr | 10 ++ src/test/ui/tuple/wrong_argument_ice-4.stderr | 5 + .../unboxed-closures-type-mismatch.stderr | 5 + 7 files changed, 97 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 580fb7c3e0f..90b59df472c 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -59,7 +59,7 @@ pub fn check_legal_trait_for_method_call( enum CallStep<'tcx> { Builtin(Ty<'tcx>), - DeferredClosure(ty::FnSig<'tcx>), + DeferredClosure(DefId, ty::FnSig<'tcx>), /// E.g., enum variant constructors. Overloaded(MethodCallee<'tcx>), } @@ -107,8 +107,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.confirm_builtin_call(call_expr, callee_expr, callee_ty, arg_exprs, expected) } - Some(CallStep::DeferredClosure(fn_sig)) => { - self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig) + Some(CallStep::DeferredClosure(def_id, fn_sig)) => { + self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, def_id, fn_sig) } Some(CallStep::Overloaded(method_callee)) => { @@ -171,7 +171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_substs: substs, }, ); - return Some(CallStep::DeferredClosure(closure_sig)); + return Some(CallStep::DeferredClosure(def_id, closure_sig)); } } @@ -533,6 +533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr: &'tcx hir::Expr<'tcx>, arg_exprs: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, + closure_def_id: DefId, fn_sig: ty::FnSig<'tcx>, ) -> Ty<'tcx> { // `fn_sig` is the *signature* of the closure being called. We @@ -555,7 +556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs, fn_sig.c_variadic, TupleArgumentsFlag::TupleArguments, - None, + Some(closure_def_id), ); fn_sig.output() diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 75976ebdf28..3a501196ed2 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -24,7 +24,7 @@ use rustc_infer::infer::TypeTrace; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, Span}; @@ -523,24 +523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("arguments to this {} are incorrect", call_name), ); // Call out where the function is defined - if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) { - let mut spans: MultiSpan = def_span.into(); - - let params = tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.body_id()) - .into_iter() - .map(|id| tcx.hir().body(id).params) - .flatten(); - - for param in params { - spans.push_span_label(param.span, String::new()); - } - - let def_kind = tcx.def_kind(def_id); - err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); - } + label_fn_like(tcx, &mut err, fn_def_id); err.emit(); break 'errors; } @@ -558,24 +541,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { DiagnosticId::Error(err_code.to_owned()), ); // Call out where the function is defined - if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) { - let mut spans: MultiSpan = def_span.into(); - - let params = tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.body_id()) - .into_iter() - .map(|id| tcx.hir().body(id).params) - .flatten(); - - for param in params { - spans.push_span_label(param.span, String::new()); - } - - let def_kind = tcx.def_kind(def_id); - err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); - } + label_fn_like(tcx, &mut err, fn_def_id); err.multipart_suggestion( "use parentheses to construct a tuple", vec![(start, '('.to_string()), (end, ')'.to_string())], @@ -613,24 +579,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("arguments to this {} are incorrect", call_name), ); // Call out where the function is defined - if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) { - let mut spans: MultiSpan = def_span.into(); - - let params = tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.body_id()) - .into_iter() - .map(|id| tcx.hir().body(id).params) - .flatten(); - - for param in params { - spans.push_span_label(param.span, String::new()); - } - - let def_kind = tcx.def_kind(def_id); - err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); - } + label_fn_like(tcx, &mut err, fn_def_id); err.emit(); break 'errors; } @@ -948,24 +897,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Call out where the function is defined - if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) { - let mut spans: MultiSpan = def_span.into(); - - let params = tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.body_id()) - .into_iter() - .flat_map(|id| tcx.hir().body(id).params) - ; - - for param in params { - spans.push_span_label(param.span, String::new()); - } - - let def_kind = tcx.def_kind(def_id); - err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); - } + label_fn_like(tcx, &mut err, fn_def_id); // And add a suggestion block for all of the parameters let suggestion_text = match suggestion_text { @@ -1790,3 +1722,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + +fn label_fn_like<'tcx>( + tcx: TyCtxt<'tcx>, + err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>, + def_id: Option, +) { + let Some(def_id) = def_id else { + return; + }; + + if let Some(def_span) = tcx.def_ident_span(def_id) { + let mut spans: MultiSpan = def_span.into(); + + let params = tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.body_id()) + .into_iter() + .map(|id| tcx.hir().body(id).params) + .flatten(); + + for param in params { + spans.push_span_label(param.span, String::new()); + } + + let def_kind = tcx.def_kind(def_id); + err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); + } else { + match tcx.hir().get_if_local(def_id) { + Some(hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(_, _, _, span, ..), + .. + })) => { + let spans: MultiSpan = (*span).into(); + + // Note: We don't point to param spans here because they overlap + // with the closure span itself + + err.span_note(spans, "closure defined here"); + } + _ => {} + } + } +} diff --git a/src/test/ui/argument-suggestions/basic.rs b/src/test/ui/argument-suggestions/basic.rs index 765b2d5d68e..3e96322d67e 100644 --- a/src/test/ui/argument-suggestions/basic.rs +++ b/src/test/ui/argument-suggestions/basic.rs @@ -22,4 +22,7 @@ fn main() { missing(); //~ ERROR this function takes swapped("", 1); //~ ERROR arguments to this function are incorrect permuted(Y {}, Z {}, X {}); //~ ERROR arguments to this function are incorrect + + let closure = |x| x; + closure(); //~ ERROR this function takes } diff --git a/src/test/ui/argument-suggestions/basic.stderr b/src/test/ui/argument-suggestions/basic.stderr index 78f82b07619..8300a22c548 100644 --- a/src/test/ui/argument-suggestions/basic.stderr +++ b/src/test/ui/argument-suggestions/basic.stderr @@ -81,7 +81,23 @@ help: reorder these arguments LL | permuted(X {}, Y {}, Z {}); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 5 previous errors +error[E0057]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/basic.rs:27:5 + | +LL | closure(); + | ^^^^^^^-- an argument is missing + | +note: closure defined here + --> $DIR/basic.rs:26:19 + | +LL | let closure = |x| x; + | ^^^ +help: provide the argument + | +LL | closure({_}); + | ~~~~~~~~~~~~ -Some errors have detailed explanations: E0061, E0308. -For more information about an error, try `rustc --explain E0061`. +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0057, E0061, E0308. +For more information about an error, try `rustc --explain E0057`. diff --git a/src/test/ui/error-codes/E0057.stderr b/src/test/ui/error-codes/E0057.stderr index a151b20f865..4b4d30a8387 100644 --- a/src/test/ui/error-codes/E0057.stderr +++ b/src/test/ui/error-codes/E0057.stderr @@ -4,6 +4,11 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied LL | let a = f(); | ^-- an argument is missing | +note: closure defined here + --> $DIR/E0057.rs:2:13 + | +LL | let f = |x| x * 3; + | ^^^ help: provide the argument | LL | let a = f({_}); @@ -15,6 +20,11 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied LL | let c = f(2, 3); | ^ - argument unexpected | +note: closure defined here + --> $DIR/E0057.rs:2:13 + | +LL | let f = |x| x * 3; + | ^^^ help: remove the extra argument | LL | let c = f(2); diff --git a/src/test/ui/tuple/wrong_argument_ice-4.stderr b/src/test/ui/tuple/wrong_argument_ice-4.stderr index 0c25b6801dc..f8dfc4cd043 100644 --- a/src/test/ui/tuple/wrong_argument_ice-4.stderr +++ b/src/test/ui/tuple/wrong_argument_ice-4.stderr @@ -8,6 +8,11 @@ LL | | let b = 1; LL | | }); | |_____- argument unexpected | +note: closure defined here + --> $DIR/wrong_argument_ice-4.rs:2:6 + | +LL | (|| {})(|| { + | ^^ help: remove the extra argument | LL | (|| {})(); diff --git a/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr b/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr index ea1ca380b1c..3241c9f8521 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr @@ -6,6 +6,11 @@ LL | let z = f(1_usize, 2); | | | arguments to this function are incorrect | +note: closure defined here + --> $DIR/unboxed-closures-type-mismatch.rs:4:17 + | +LL | let mut f = |x: isize, y: isize| -> isize { x + y }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: change the type of the numeric literal from `usize` to `isize` | LL | let z = f(1_isize, 2);