diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 723f13dbe8d31..3098eb20be3ac 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -1946,6 +1946,39 @@ pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
     }
 }
 
+/// Grammatical tool for displaying messages to end users in a nice form.
+///
+/// Returns "an" if the given string starts with a vowel, and "a" otherwise.
+pub fn a_or_an(s: &str) -> &'static str {
+    let mut chars = s.chars();
+    let Some(mut first_alpha_char) = chars.next() else {
+        return "a";
+    };
+    if first_alpha_char == '`' {
+        let Some(next) = chars.next() else {
+            return "a";
+        };
+        first_alpha_char = next;
+    }
+    if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
+        "an"
+    } else {
+        "a"
+    }
+}
+
+/// Grammatical tool for displaying messages to end users in a nice form.
+///
+/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
+pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
+    match v.len() {
+        0 => "".to_string(),
+        1 => v[0].to_string(),
+        2 => format!("{} and {}", v[0], v[1]),
+        _ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])),
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum TerminalUrl {
     No,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 1fa1da93018af..c0d971523548e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -17,7 +17,8 @@ use itertools::Itertools;
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
-    codes::*, pluralize, Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey,
+    a_or_an, codes::*, display_list_with_comma_and, pluralize, Applicability, Diag,
+    ErrorGuaranteed, MultiSpan, StashKey,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -795,6 +796,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         call_expr,
                         None,
                         Some(mismatch_idx),
+                        &matched_inputs,
+                        &formal_and_expected_inputs,
                         is_method,
                     );
                     suggest_confusable(&mut err);
@@ -881,6 +884,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
             err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect"));
 
+            self.label_generic_mismatches(
+                &mut err,
+                fn_def_id,
+                &matched_inputs,
+                &provided_arg_tys,
+                &formal_and_expected_inputs,
+                is_method,
+            );
+
             if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind
                 && provided_idx.as_usize() == expected_idx.as_usize()
             {
@@ -909,6 +921,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 call_expr,
                 Some(expected_ty),
                 Some(expected_idx.as_usize()),
+                &matched_inputs,
+                &formal_and_expected_inputs,
                 is_method,
             );
             suggest_confusable(&mut err);
@@ -1247,6 +1261,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
+        self.label_generic_mismatches(
+            &mut err,
+            fn_def_id,
+            &matched_inputs,
+            &provided_arg_tys,
+            &formal_and_expected_inputs,
+            is_method,
+        );
+
         // Incorporate the argument changes in the removal suggestion.
         // When a type is *missing*, and the rest are additional, we want to suggest these with a
         // multipart suggestion, but in order to do so we need to figure out *where* the arg that
@@ -1294,7 +1317,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         // Call out where the function is defined
-        self.label_fn_like(&mut err, fn_def_id, callee_ty, call_expr, None, None, is_method);
+        self.label_fn_like(
+            &mut err,
+            fn_def_id,
+            callee_ty,
+            call_expr,
+            None,
+            None,
+            &matched_inputs,
+            &formal_and_expected_inputs,
+            is_method,
+        );
 
         // And add a suggestion block for all of the parameters
         let suggestion_text = match suggestion_text {
@@ -2054,6 +2087,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty: Option<Ty<'tcx>>,
         // A specific argument should be labeled, instead of all of them
         expected_idx: Option<usize>,
+        matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
+        formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
         is_method: bool,
     ) {
         let Some(mut def_id) = callable_def_id else {
@@ -2145,21 +2180,164 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         {
             let mut spans: MultiSpan = def_span.into();
 
-            let params = self
+            let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
+            let mut generics_with_unmatched_params = Vec::new();
+
+            let check_for_matched_generics = || {
+                if matched_inputs.iter().any(|x| x.is_some())
+                    && params_with_generics.iter().any(|x| x.0.is_some())
+                {
+                    for (idx, (generic, _)) in params_with_generics.iter().enumerate() {
+                        // Param has to have a generic and be matched to be relevant
+                        if matched_inputs[idx.into()].is_none() {
+                            continue;
+                        }
+
+                        let Some(generic) = generic else {
+                            continue;
+                        };
+
+                        for unmatching_idx in idx + 1..params_with_generics.len() {
+                            if matched_inputs[unmatching_idx.into()].is_none()
+                                && let Some(unmatched_idx_param_generic) =
+                                    params_with_generics[unmatching_idx].0
+                                && unmatched_idx_param_generic.name.ident() == generic.name.ident()
+                            {
+                                // We found a parameter that didn't match that needed to
+                                return true;
+                            }
+                        }
+                    }
+                }
+                false
+            };
+
+            let check_for_matched_generics = check_for_matched_generics();
+
+            for (idx, (generic_param, param)) in
+                params_with_generics.iter().enumerate().filter(|(idx, _)| {
+                    check_for_matched_generics
+                        || expected_idx.map_or(true, |expected_idx| expected_idx == *idx)
+                })
+            {
+                let Some(generic_param) = generic_param else {
+                    spans.push_span_label(param.span, "");
+                    continue;
+                };
+
+                let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics
+                    .iter()
+                    .enumerate()
+                    .filter(|(other_idx, (other_generic_param, _))| {
+                        if *other_idx == idx {
+                            return false;
+                        }
+                        let Some(other_generic_param) = other_generic_param else {
+                            return false;
+                        };
+                        if matched_inputs[idx.into()].is_none()
+                            && matched_inputs[(*other_idx).into()].is_none()
+                        {
+                            return false;
+                        }
+                        if matched_inputs[idx.into()].is_some()
+                            && matched_inputs[(*other_idx).into()].is_some()
+                        {
+                            return false;
+                        }
+                        other_generic_param.name.ident() == generic_param.name.ident()
+                    })
+                    .map(|(other_idx, (_, other_param))| (other_idx, *other_param))
+                    .collect();
+
+                if !other_params_matched.is_empty() {
+                    let other_param_matched_names: Vec<String> = other_params_matched
+                        .iter()
+                        .map(|(_, other_param)| {
+                            if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind {
+                                format!("`{ident}`")
+                            } else {
+                                "{unknown}".to_string()
+                            }
+                        })
+                        .collect();
+
+                    let matched_ty = self
+                        .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
+                        .sort_string(self.tcx);
+
+                    if matched_inputs[idx.into()].is_some() {
+                        spans.push_span_label(
+                            param.span,
+                            format!(
+                                "{} {} to match the {} type of this parameter",
+                                display_list_with_comma_and(&other_param_matched_names),
+                                format!(
+                                    "need{}",
+                                    pluralize!(if other_param_matched_names.len() == 1 {
+                                        0
+                                    } else {
+                                        1
+                                    })
+                                ),
+                                matched_ty,
+                            ),
+                        );
+                    } else {
+                        spans.push_span_label(
+                            param.span,
+                            format!(
+                                "this parameter needs to match the {} type of {}",
+                                matched_ty,
+                                display_list_with_comma_and(&other_param_matched_names),
+                            ),
+                        );
+                    }
+                    generics_with_unmatched_params.push(generic_param);
+                } else {
+                    spans.push_span_label(param.span, "");
+                }
+            }
+
+            for generic_param in self
                 .tcx
                 .hir()
                 .get_if_local(def_id)
-                .and_then(|node| node.body_id())
-                .into_iter()
-                .flat_map(|id| self.tcx.hir().body(id).params)
-                .skip(if is_method { 1 } else { 0 });
-
-            for (_, param) in params
+                .and_then(|node| node.generics())
                 .into_iter()
-                .enumerate()
-                .filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx))
+                .flat_map(|x| x.params)
+                .filter(|x| {
+                    generics_with_unmatched_params.iter().any(|y| x.name.ident() == y.name.ident())
+                })
             {
-                spans.push_span_label(param.span, "");
+                let param_idents_matching: Vec<String> = params_with_generics
+                    .iter()
+                    .filter(|(generic, _)| {
+                        if let Some(generic) = generic {
+                            generic.name.ident() == generic_param.name.ident()
+                        } else {
+                            false
+                        }
+                    })
+                    .map(|(_, param)| {
+                        if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind {
+                            format!("`{ident}`")
+                        } else {
+                            "{unknown}".to_string()
+                        }
+                    })
+                    .collect();
+
+                if !param_idents_matching.is_empty() {
+                    spans.push_span_label(
+                        generic_param.span,
+                        format!(
+                            "{} all reference this parameter {}",
+                            display_list_with_comma_and(&param_idents_matching),
+                            generic_param.name.ident().name,
+                        ),
+                    );
+                }
             }
 
             err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
@@ -2225,6 +2403,115 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         }
     }
+
+    fn label_generic_mismatches(
+        &self,
+        err: &mut Diag<'_>,
+        callable_def_id: Option<DefId>,
+        matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
+        provided_arg_tys: &IndexVec<ProvidedIdx, (Ty<'tcx>, Span)>,
+        formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
+        is_method: bool,
+    ) {
+        let Some(def_id) = callable_def_id else {
+            return;
+        };
+
+        let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
+
+        for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() {
+            if matched_inputs[idx.into()].is_none() {
+                continue;
+            }
+
+            let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else {
+                continue;
+            };
+
+            let Some(generic_param) = generic_param else {
+                continue;
+            };
+
+            let mut idxs_matched: Vec<usize> = vec![];
+            for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter(
+                |(other_idx, (other_generic_param, _))| {
+                    if *other_idx == idx {
+                        return false;
+                    }
+                    let Some(other_generic_param) = other_generic_param else {
+                        return false;
+                    };
+                    if matched_inputs[(*other_idx).into()].is_some() {
+                        return false;
+                    }
+                    other_generic_param.name.ident() == generic_param.name.ident()
+                },
+            ) {
+                idxs_matched.push(other_idx.into());
+            }
+
+            if idxs_matched.is_empty() {
+                continue;
+            }
+
+            let expected_display_type = self
+                .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
+                .sort_string(self.tcx);
+            let label = if idxs_matched.len() == params_with_generics.len() - 1 {
+                format!(
+                    "expected all arguments to be this {} type because they need to match the type of this parameter",
+                    expected_display_type
+                )
+            } else {
+                format!(
+                    "expected some other arguments to be {} {} type to match the type of this parameter",
+                    a_or_an(&expected_display_type),
+                    expected_display_type,
+                )
+            };
+
+            err.span_label(*matched_arg_span, label);
+        }
+    }
+
+    fn get_hir_params_with_generics(
+        &self,
+        def_id: DefId,
+        is_method: bool,
+    ) -> Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)> {
+        let fn_node = self.tcx.hir().get_if_local(def_id);
+
+        let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node
+            .and_then(|node| node.fn_decl())
+            .into_iter()
+            .flat_map(|decl| decl.inputs)
+            .skip(if is_method { 1 } else { 0 })
+            .map(|param| {
+                if let hir::TyKind::Path(QPath::Resolved(
+                    _,
+                    hir::Path { res: Res::Def(_, res_def_id), .. },
+                )) = param.kind
+                {
+                    fn_node
+                        .and_then(|node| node.generics())
+                        .into_iter()
+                        .flat_map(|generics| generics.params)
+                        .find(|gen| &gen.def_id.to_def_id() == res_def_id)
+                } else {
+                    None
+                }
+            })
+            .collect();
+
+        let params: Vec<&hir::Param<'_>> = fn_node
+            .and_then(|node| node.body_id())
+            .into_iter()
+            .flat_map(|id| self.tcx.hir().body(id).params)
+            .skip(if is_method { 1 } else { 0 })
+            .collect();
+
+        generic_params.into_iter().zip(params).collect()
+    }
 }
 
 struct FindClosureArg<'tcx> {
diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr
index e4cb0915a1090..1f1e303ea4c67 100644
--- a/tests/ui/async-await/coroutine-desc.stderr
+++ b/tests/ui/async-await/coroutine-desc.stderr
@@ -5,6 +5,7 @@ LL |     fun(async {}, async {});
    |     --- --------  ^^^^^^^^ expected `async` block, found a different `async` block
    |     |   |
    |     |   the expected `async` block
+   |     |   expected all arguments to be this `async` block type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}`
@@ -13,14 +14,18 @@ note: function defined here
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the `async` block type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the `async` block type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error[E0308]: mismatched types
   --> $DIR/coroutine-desc.rs:12:16
    |
 LL |     fun(one(), two());
-   |     ---        ^^^^^ expected future, found a different future
-   |     |
+   |     --- -----  ^^^^^ expected future, found a different future
+   |     |   |
+   |     |   expected all arguments to be this future type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = help: consider `await`ing on both `Future`s
@@ -29,15 +34,19 @@ note: function defined here
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the future type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the future type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error[E0308]: mismatched types
   --> $DIR/coroutine-desc.rs:14:26
    |
 LL |     fun((async || {})(), (async || {})());
-   |     ---           --     ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
-   |     |             |
-   |     |             the expected `async` closure body
+   |     --- ---------------  ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
+   |     |   |         |
+   |     |   |         the expected `async` closure body
+   |     |   expected all arguments to be this `async` closure body type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}`
@@ -46,7 +55,10 @@ note: function defined here
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the `async` closure body type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the `async` closure body type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
index 498ef33d52ecc..46723c5a297f7 100644
--- a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
+++ b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
@@ -2,8 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18
    |
 LL |     test(&mut 7, &7);
-   |     ----         ^^ types differ in mutability
-   |     |
+   |     ---- ------  ^^ types differ in mutability
+   |     |    |
+   |     |    expected all arguments to be this `&mut {integer}` type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected mutable reference `&mut {integer}`
@@ -12,7 +13,10 @@ note: function defined here
   --> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4
    |
 LL | fn test<T>(_a: T, _b: T) {}
-   |    ^^^^           -----
+   |    ^^^^ -  -----  ----- this parameter needs to match the `&mut {integer}` type of `_a`
+   |         |  |
+   |         |  `_b` needs to match the `&mut {integer}` type of this parameter
+   |         `_a` and `_b` all reference this parameter T
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/fn/fn-item-type.stderr b/tests/ui/fn/fn-item-type.stderr
index da90b8b81c855..76cdbcceac841 100644
--- a/tests/ui/fn/fn-item-type.stderr
+++ b/tests/ui/fn/fn-item-type.stderr
@@ -2,8 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:22:19
    |
 LL |     eq(foo::<u8>, bar::<u8>);
-   |     --            ^^^^^^^^^ expected fn item, found a different fn item
-   |     |
+   |     -- ---------  ^^^^^^^^^ expected fn item, found a different fn item
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -13,15 +14,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:29:19
    |
 LL |     eq(foo::<u8>, foo::<i8>);
-   |     --            ^^^^^^^^^ expected `u8`, found `i8`
-   |     |
+   |     -- ---------  ^^^^^^^^^ expected `u8`, found `i8`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -31,15 +36,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:34:23
    |
 LL |     eq(bar::<String>, bar::<Vec<u8>>);
-   |     --                ^^^^^^^^^^^^^^ expected `String`, found `Vec<u8>`
-   |     |
+   |     -- -------------  ^^^^^^^^^^^^^^ expected `String`, found `Vec<u8>`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {bar::<String>}`
@@ -49,15 +58,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:40:26
    |
 LL |     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
-   |     --                   ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
-   |     |
+   |     -- ----------------  ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn() {<u8 as Foo>::foo}`
@@ -67,15 +80,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn()`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:45:19
    |
 LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
-   |     --            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
-   |     |
+   |     -- ---------  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -85,7 +102,10 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs
new file mode 100644
index 0000000000000..2bd10e762d9a0
--- /dev/null
+++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs
@@ -0,0 +1,14 @@
+fn foo<T>(a: T, b: T) {}
+fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+fn foo_multi_generics<S, T>(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {}
+
+fn main() {
+    foo(1, 2.);
+    //~^  ERROR mismatched types
+    foo_multi_same("a", "b", false, true, (), 32);
+    //~^  ERROR arguments to this function are incorrect
+    foo_multi_generics("a", "b", "c", true, false, 32, 2.);
+    //~^  ERROR arguments to this function are incorrect
+    foo_multi_same("a", 1, 2, "d", "e", 32);
+    //~^  ERROR arguments to this function are incorrect
+}
diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr
new file mode 100644
index 0000000000000..a845dfabe93b7
--- /dev/null
+++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr
@@ -0,0 +1,97 @@
+error[E0308]: mismatched types
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:6:12
+   |
+LL |     foo(1, 2.);
+   |     --- -  ^^ expected integer, found floating-point number
+   |     |   |
+   |     |   expected all arguments to be this integer type because they need to match the type of this parameter
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:1:4
+   |
+LL | fn foo<T>(a: T, b: T) {}
+   |    ^^^ -  ----  ---- this parameter needs to match the integer type of `a`
+   |        |  |
+   |        |  `b` needs to match the integer type of this parameter
+   |        `a` and `b` all reference this parameter T
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:8:5
+   |
+LL |     foo_multi_same("a", "b", false, true, (), 32);
+   |     ^^^^^^^^^^^^^^ ---  ---  -----  ----  -- expected `&str`, found `()`
+   |                    |    |    |      |
+   |                    |    |    |      expected `&str`, found `bool`
+   |                    |    |    expected `&str`, found `bool`
+   |                    |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4
+   |
+LL | fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+   |    ^^^^^^^^^^^^^^ -  ----  ----  ----  ----  ----  ------
+   |                   |  |     |     |     |     |
+   |                   |  |     |     |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     `c`, `d` and `e` need to match the `&str` type of this parameter
+   |                   |  `c`, `d` and `e` need to match the `&str` type of this parameter
+   |                   `a`, `b`, `c`, `d` and `e` all reference this parameter T
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:10:5
+   |
+LL |     foo_multi_generics("a", "b", "c", true, false, 32, 2.);
+   |     ^^^^^^^^^^^^^^^^^^ ---  ---  ---  ----  -----  --  -- expected integer, found floating-point number
+   |                        |    |    |    |     |      |
+   |                        |    |    |    |     |      expected some other arguments to be an integer type to match the type of this parameter
+   |                        |    |    |    |     expected `&str`, found `bool`
+   |                        |    |    |    expected `&str`, found `bool`
+   |                        |    |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                        |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                        expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:3:4
+   |
+LL | fn foo_multi_generics<S, T>(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {}
+   |    ^^^^^^^^^^^^^^^^^^ -  -  ----  ----  ----  ----  ----  ----  ---- this parameter needs to match the integer type of `f`
+   |                       |  |  |     |     |     |     |     |
+   |                       |  |  |     |     |     |     |     `g` needs to match the integer type of this parameter
+   |                       |  |  |     |     |     |     this parameter needs to match the `&str` type of `a`, `b` and `c`
+   |                       |  |  |     |     |     this parameter needs to match the `&str` type of `a`, `b` and `c`
+   |                       |  |  |     |     `d` and `e` need to match the `&str` type of this parameter
+   |                       |  |  |     `d` and `e` need to match the `&str` type of this parameter
+   |                       |  |  `d` and `e` need to match the `&str` type of this parameter
+   |                       |  `a`, `b`, `c`, `d` and `e` all reference this parameter T
+   |                       `f` and `g` all reference this parameter S
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:12:5
+   |
+LL |     foo_multi_same("a", 1, 2, "d", "e", 32);
+   |     ^^^^^^^^^^^^^^ ---  -  -  ---  --- expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    |    |  |  |
+   |                    |    |  |  expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    |    |  expected `&str`, found integer
+   |                    |    expected `&str`, found integer
+   |                    expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4
+   |
+LL | fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+   |    ^^^^^^^^^^^^^^ -  ----  ----  ----  ----  ----  ------
+   |                   |  |     |     |     |     |
+   |                   |  |     |     |     |     `b` and `c` need to match the `&str` type of this parameter
+   |                   |  |     |     |     `b` and `c` need to match the `&str` type of this parameter
+   |                   |  |     |     this parameter needs to match the `&str` type of `a`, `d` and `e`
+   |                   |  |     this parameter needs to match the `&str` type of `a`, `d` and `e`
+   |                   |  `b` and `c` need to match the `&str` type of this parameter
+   |                   `a`, `b`, `c`, `d` and `e` all reference this parameter T
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.