-
Notifications
You must be signed in to change notification settings - Fork 14k
Only point out a single function parameter if we have a single arg incompatibility #99646
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -440,30 +440,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
| call_expr: &hir::Expr<'tcx>, | ||
| ) { | ||
| // Next, let's construct the error | ||
| let (error_span, full_call_span, ctor_of) = match &call_expr.kind { | ||
| let (error_span, full_call_span, ctor_of, is_method) = match &call_expr.kind { | ||
| hir::ExprKind::Call( | ||
| hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. }, | ||
| _, | ||
| ) => { | ||
| if let Res::Def(DefKind::Ctor(of, _), _) = | ||
| self.typeck_results.borrow().qpath_res(qpath, *hir_id) | ||
| { | ||
| (call_span, *span, Some(of)) | ||
| (call_span, *span, Some(of), false) | ||
| } else { | ||
| (call_span, *span, None) | ||
| (call_span, *span, None, false) | ||
| } | ||
| } | ||
| hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None), | ||
| hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false), | ||
| hir::ExprKind::MethodCall(path_segment, _, span) => { | ||
| let ident_span = path_segment.ident.span; | ||
| let ident_span = if let Some(args) = path_segment.args { | ||
| ident_span.with_hi(args.span_ext.hi()) | ||
| } else { | ||
| ident_span | ||
| }; | ||
| ( | ||
| *span, ident_span, None, // methods are never ctors | ||
| ) | ||
| // methods are never ctors | ||
| (*span, ident_span, None, true) | ||
| } | ||
| k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), | ||
| }; | ||
|
|
@@ -659,7 +658,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
| Applicability::MachineApplicable, | ||
| ); | ||
| }; | ||
| self.label_fn_like(&mut err, fn_def_id, callee_ty); | ||
| self.label_fn_like(&mut err, fn_def_id, callee_ty, Some(mismatch_idx), is_method); | ||
| err.emit(); | ||
| return; | ||
| } | ||
|
|
@@ -701,16 +700,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
| } | ||
|
|
||
| errors.drain_filter(|error| { | ||
| let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(error)) = error else { return false }; | ||
| let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = error else { return false }; | ||
| let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; | ||
| let (expected_ty, _) = formal_and_expected_inputs[*expected_idx]; | ||
| let cause = &self.misc(provided_span); | ||
| let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); | ||
| if let Some(e) = error { | ||
| if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) { | ||
| self.report_and_explain_type_error(trace, e).emit(); | ||
| return true; | ||
| } | ||
| if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) { | ||
| self.report_and_explain_type_error(trace, e).emit(); | ||
| return true; | ||
| } | ||
| false | ||
| }); | ||
|
|
@@ -749,7 +746,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
| format!("arguments to this {} are incorrect", call_name), | ||
| ); | ||
| // Call out where the function is defined | ||
| self.label_fn_like(&mut err, fn_def_id, callee_ty); | ||
| self.label_fn_like( | ||
| &mut err, | ||
| fn_def_id, | ||
| callee_ty, | ||
| Some(expected_idx.as_usize()), | ||
| is_method, | ||
| ); | ||
| err.emit(); | ||
| return; | ||
| } | ||
|
|
@@ -1031,7 +1034,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
| } | ||
|
|
||
| // Call out where the function is defined | ||
| self.label_fn_like(&mut err, fn_def_id, callee_ty); | ||
| self.label_fn_like(&mut err, fn_def_id, callee_ty, None, is_method); | ||
|
|
||
| // And add a suggestion block for all of the parameters | ||
| let suggestion_text = match suggestion_text { | ||
|
|
@@ -1781,6 +1784,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
| err: &mut Diagnostic, | ||
| callable_def_id: Option<DefId>, | ||
| callee_ty: Option<Ty<'tcx>>, | ||
| // A specific argument should be labeled, instead of all of them | ||
| expected_idx: Option<usize>, | ||
|
||
| is_method: bool, | ||
| ) { | ||
| let Some(mut def_id) = callable_def_id else { | ||
| return; | ||
|
|
@@ -1881,14 +1887,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
| .get_if_local(def_id) | ||
| .and_then(|node| node.body_id()) | ||
| .into_iter() | ||
| .flat_map(|id| self.tcx.hir().body(id).params); | ||
| .flat_map(|id| self.tcx.hir().body(id).params) | ||
| .skip(if is_method { 1 } else { 0 }); | ||
|
|
||
| for param in params { | ||
| for (_, param) in params | ||
| .into_iter() | ||
| .enumerate() | ||
| .filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx)) | ||
| { | ||
| spans.push_span_label(param.span, ""); | ||
| } | ||
|
|
||
| let def_kind = self.tcx.def_kind(def_id); | ||
| err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); | ||
| } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id) | ||
| && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind | ||
| { | ||
| let param = expected_idx | ||
| .and_then(|expected_idx| self.tcx.hir().body(*body).params.get(expected_idx)); | ||
| let (kind, span) = if let Some(param) = param { | ||
| ("closure parameter", param.span) | ||
| } else { | ||
| ("closure", self.tcx.def_span(def_id)) | ||
| }; | ||
| err.span_note(span, &format!("{} defined here", kind)); | ||
| } else { | ||
| let def_kind = self.tcx.def_kind(def_id); | ||
| err.span_note( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| struct Qux; | ||
|
|
||
| impl Qux { | ||
| fn foo( | ||
| &self, | ||
| a: i32, | ||
| b: i32, | ||
| c: i32, | ||
| d: i32, | ||
| e: i32, | ||
| f: i32, | ||
| g: i32, | ||
| h: i32, | ||
| i: i32, | ||
| j: i32, | ||
| k: i32, | ||
| l: i32, | ||
| ) { | ||
| } | ||
| } | ||
|
|
||
| fn what( | ||
| qux: &Qux, | ||
| a: i32, | ||
| b: i32, | ||
| c: i32, | ||
| d: i32, | ||
| e: i32, | ||
| f: &i32, | ||
| g: i32, | ||
| h: i32, | ||
| i: i32, | ||
| j: i32, | ||
| k: i32, | ||
| l: i32, | ||
| ) { | ||
| qux.foo(a, b, c, d, e, f, g, h, i, j, k, l); | ||
| //~^ ERROR mismatched types | ||
| } | ||
|
|
||
| fn main() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| error[E0308]: mismatched types | ||
| --> $DIR/too-long.rs:37:28 | ||
| | | ||
| LL | qux.foo(a, b, c, d, e, f, g, h, i, j, k, l); | ||
| | --- ^ expected `i32`, found `&i32` | ||
| | | | ||
| | arguments to this function are incorrect | ||
| | | ||
| note: associated function defined here | ||
| --> $DIR/too-long.rs:4:8 | ||
| | | ||
| LL | fn foo( | ||
| | ^^^ | ||
| ... | ||
| LL | f: i32, | ||
|
||
| | ------ | ||
| help: consider dereferencing the borrow | ||
| | | ||
| LL | qux.foo(a, b, c, d, e, *f, g, h, i, j, k, l); | ||
| | + | ||
|
|
||
| error: aborting due to previous error | ||
|
|
||
| For more information about this error, try `rustc --explain E0308`. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change means that we no longer include the comma in the param span, right? I don't know if that is a good call 🤔
Maybe we can address the span issue on the other end, by creating a new span that is
param.pat.span.to(param.ty.map_or(param.pat.span, |ty| ty.span). I guess it depends on what we've used the param's span for elsewhere (even though there haven't been any visible changes in our test suite from this... I guess I'm fine either way :-/There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think nobody used it, evidenced by the lack of UI test changes.
This makes it more consistent with regular fn signatures' spans.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine, let's go ahead with that change then. We can revisit this if we ever need the param + comma (I'm sure, for removal suggestions) :)