about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs50
-rw-r--r--tests/ui/argument-suggestions/issue-100478.stderr16
-rw-r--r--tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs12
-rw-r--r--tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr28
4 files changed, 91 insertions, 15 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 36abd7c8555..b80a2af3100 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1589,26 +1589,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // e.g. `reuse HasSelf::method;` should suggest `reuse HasSelf::method($args);`.
                 full_call_span.shrink_to_hi()
             };
+
+            // Controls how the arguments should be listed in the suggestion.
+            enum ArgumentsFormatting {
+                SingleLine,
+                Multiline { fallback_indent: String, brace_indent: String },
+            }
+            let arguments_formatting = {
+                let mut provided_inputs = matched_inputs.iter().filter_map(|a| *a);
+                if let Some(brace_indent) = source_map.indentation_before(suggestion_span)
+                    && let Some(first_idx) = provided_inputs.by_ref().next()
+                    && let Some(last_idx) = provided_inputs.by_ref().next()
+                    && let (_, first_span) = provided_arg_tys[first_idx]
+                    && let (_, last_span) = provided_arg_tys[last_idx]
+                    && source_map.is_multiline(first_span.to(last_span))
+                    && let Some(fallback_indent) = source_map.indentation_before(first_span)
+                {
+                    ArgumentsFormatting::Multiline { fallback_indent, brace_indent }
+                } else {
+                    ArgumentsFormatting::SingleLine
+                }
+            };
+
             let mut suggestion = "(".to_owned();
             let mut needs_comma = false;
             for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() {
                 if needs_comma {
-                    suggestion += ", ";
-                } else {
-                    needs_comma = true;
+                    suggestion += ",";
+                }
+                match &arguments_formatting {
+                    ArgumentsFormatting::SingleLine if needs_comma => suggestion += " ",
+                    ArgumentsFormatting::SingleLine => {}
+                    ArgumentsFormatting::Multiline { .. } => suggestion += "\n",
                 }
-                let suggestion_text = if let Some(provided_idx) = provided_idx
+                needs_comma = true;
+                let (suggestion_span, suggestion_text) = if let Some(provided_idx) = provided_idx
                     && let (_, provided_span) = provided_arg_tys[*provided_idx]
                     && let Ok(arg_text) = source_map.span_to_snippet(provided_span)
                 {
-                    arg_text
+                    (Some(provided_span), arg_text)
                 } else {
                     // Propose a placeholder of the correct type
                     let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
-                    ty_to_snippet(expected_ty, expected_idx)
+                    (None, ty_to_snippet(expected_ty, expected_idx))
                 };
+                if let ArgumentsFormatting::Multiline { fallback_indent, .. } =
+                    &arguments_formatting
+                {
+                    let indent = suggestion_span
+                        .and_then(|span| source_map.indentation_before(span))
+                        .unwrap_or_else(|| fallback_indent.clone());
+                    suggestion += &indent;
+                }
                 suggestion += &suggestion_text;
             }
+            if let ArgumentsFormatting::Multiline { brace_indent, .. } = arguments_formatting {
+                suggestion += ",\n";
+                suggestion += &brace_indent;
+            }
             suggestion += ")";
             err.span_suggestion_verbose(
                 suggestion_span,
diff --git a/tests/ui/argument-suggestions/issue-100478.stderr b/tests/ui/argument-suggestions/issue-100478.stderr
index 8889a0ab5df..81dbff2f000 100644
--- a/tests/ui/argument-suggestions/issue-100478.stderr
+++ b/tests/ui/argument-suggestions/issue-100478.stderr
@@ -75,12 +75,16 @@ LL | fn foo(p1: T1, p2: Arc<T2>, p3: T3, p4: Arc<T4>, p5: T5, p6: T6, p7: T7, p8
    |    ^^^         -----------
 help: provide the argument
    |
-LL -     foo(
-LL -
-LL -         p1, //p2,
-LL -         p3, p4, p5, p6, p7, p8,
-LL -     );
-LL +     foo(p1, /* Arc<T2> */, p3, p4, p5, p6, p7, p8);
+LL ~     foo(
+LL +         p1,
+LL +         /* Arc<T2> */,
+LL +         p3,
+LL +         p4,
+LL +         p5,
+LL +         p6,
+LL +         p7,
+LL +         p8,
+LL ~     );
    |
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs
index b2f80ba1bf6..3b12ea1a736 100644
--- a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs
+++ b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs
@@ -46,9 +46,21 @@ impl Bar {
     }
 }
 
+fn function_with_lots_of_arguments(a: i32, b: char, c: i32, d: i32, e: i32, f: i32) {}
+
 fn main() {
     foo(1, 2, 3);
     //~^ ERROR function takes 4 arguments but 3
     bar(1, 2, 3);
     //~^ ERROR function takes 6 arguments but 3
+
+    let variable_name = 42;
+    function_with_lots_of_arguments(
+        variable_name,
+        variable_name,
+        variable_name,
+        variable_name,
+        variable_name,
+    );
+    //~^^^^^^^ ERROR this function takes 6 arguments but 5 arguments were supplied [E0061]
 }
diff --git a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr
index 6af7671af03..dda9b398a83 100644
--- a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr
+++ b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr
@@ -52,7 +52,7 @@ LL |         <$from>::$method(8, /* u8 */)
    |                           ++++++++++
 
 error[E0061]: this function takes 4 arguments but 3 arguments were supplied
-  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:50:5
+  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:52:5
    |
 LL |     foo(1, 2, 3);
    |     ^^^--------- argument #4 of type `isize` is missing
@@ -68,7 +68,7 @@ LL |     foo(1, 2, 3, /* isize */);
    |                +++++++++++++
 
 error[E0061]: this function takes 6 arguments but 3 arguments were supplied
-  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:52:5
+  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:54:5
    |
 LL |     bar(1, 2, 3);
    |     ^^^--------- three arguments of type `i32`, `i32`, and `i32` are missing
@@ -83,6 +83,28 @@ help: provide the arguments
 LL |     bar(1, 2, 3, /* i32 */, /* i32 */, /* i32 */);
    |                +++++++++++++++++++++++++++++++++
 
-error: aborting due to 5 previous errors
+error[E0061]: this function takes 6 arguments but 5 arguments were supplied
+  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:58:5
+   |
+LL |     function_with_lots_of_arguments(
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         variable_name,
+LL |         variable_name,
+   |         ------------- argument #2 of type `char` is missing
+   |
+note: function defined here
+  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:49:4
+   |
+LL | fn function_with_lots_of_arguments(a: i32, b: char, c: i32, d: i32, e: i32, f: i32) {}
+   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         -------
+help: provide the argument
+   |
+LL |     function_with_lots_of_arguments(
+LL |         variable_name,
+LL ~         /* char */,
+LL ~         variable_name,
+   |
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0061`.