diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 63148ab517c..c6d72700b3f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -951,6 +951,32 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator>) -> bool { return err.emit(); } + // Special case, we found an extra argument is provided, which is very common in practice. + // but there is a obviously better removing suggestion compared to the current one, + // try to find the argument with Error type, if we removed it all the types will become good, + // then we will replace the current suggestion. + if let [Error::Extra(provided_idx)] = &errors[..] { + let remove_idx_is_perfect = |idx: usize| -> bool { + let removed_arg_tys = provided_arg_tys + .iter() + .enumerate() + .filter_map(|(j, arg)| if idx == j { None } else { Some(arg) }) + .collect::>(); + std::iter::zip(formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all( + |((expected_ty, _), (provided_ty, _))| { + !provided_ty.references_error() + && self.can_coerce(*provided_ty, *expected_ty) + }, + ) + }; + + if !remove_idx_is_perfect(provided_idx.as_usize()) { + if let Some(i) = (0..provided_args.len()).find(|&i| remove_idx_is_perfect(i)) { + errors = vec![Error::Extra(ProvidedIdx::from_usize(i))]; + } + } + } + let mut err = if formal_and_expected_inputs.len() == provided_args.len() { struct_span_code_err!( self.dcx(), diff --git a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs new file mode 100644 index 00000000000..fa1802283c3 --- /dev/null +++ b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs @@ -0,0 +1,21 @@ +fn add_one(x: i32) -> i32 { + x + 1 +} + +fn add_two(x: i32, y: i32) -> i32 { + x + y +} + +fn main() { + add_one(2, 2); //~ ERROR this function takes 1 argument but 2 arguments were supplied + add_one(no_such_local, 10); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 1 argument but 2 arguments were supplied + add_one(10, no_such_local); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 1 argument but 2 arguments were supplied + add_two(10, no_such_local, 10); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 2 arguments but 3 arguments were supplied + add_two(no_such_local, 10, 10); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 2 arguments but 3 arguments were supplied + add_two(10, 10, no_such_local); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 2 arguments but 3 arguments were supplied +} diff --git a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr new file mode 100644 index 00000000000..7c4daa3ffe9 --- /dev/null +++ b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr @@ -0,0 +1,124 @@ +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:11:13 + | +LL | add_one(no_such_local, 10); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:13:17 + | +LL | add_one(10, no_such_local); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:15:17 + | +LL | add_two(10, no_such_local, 10); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:17:13 + | +LL | add_two(no_such_local, 10, 10); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:19:21 + | +LL | add_two(10, 10, no_such_local); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:10:5 + | +LL | add_one(2, 2); + | ^^^^^^^ --- + | | | + | | unexpected argument of type `{integer}` + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:1:4 + | +LL | fn add_one(x: i32) -> i32 { + | ^^^^^^^ ------ + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:11:5 + | +LL | add_one(no_such_local, 10); + | ^^^^^^^ --------------- + | | + | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:1:4 + | +LL | fn add_one(x: i32) -> i32 { + | ^^^^^^^ ------ + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:13:5 + | +LL | add_one(10, no_such_local); + | ^^^^^^^ --------------- + | | | + | | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:1:4 + | +LL | fn add_one(x: i32) -> i32 { + | ^^^^^^^ ------ + +error[E0061]: this function takes 2 arguments but 3 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:15:5 + | +LL | add_two(10, no_such_local, 10); + | ^^^^^^^ --------------- + | | | + | | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:5:4 + | +LL | fn add_two(x: i32, y: i32) -> i32 { + | ^^^^^^^ ------ ------ + +error[E0061]: this function takes 2 arguments but 3 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:17:5 + | +LL | add_two(no_such_local, 10, 10); + | ^^^^^^^ --------------- + | | + | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:5:4 + | +LL | fn add_two(x: i32, y: i32) -> i32 { + | ^^^^^^^ ------ ------ + +error[E0061]: this function takes 2 arguments but 3 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:19:5 + | +LL | add_two(10, 10, no_such_local); + | ^^^^^^^ --------------- + | | | + | | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:5:4 + | +LL | fn add_two(x: i32, y: i32) -> i32 { + | ^^^^^^^ ------ ------ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0061, E0425. +For more information about an error, try `rustc --explain E0061`.