Rollup merge of #121595 - strottos:issue_116615, r=compiler-errors

Better reporting on generic argument mismatchs

This allows better reporting as per issue #116615 .

If you have a function:
```
fn foo(a: T, b: T) {}
```
and call it like so:
```
foo(1, 2.)
```
it'll give improved error reported similar to the following:
```
error[E0308]: mismatched types
 --> generic-mismatch-reporting-issue-116615.rs:6:12
  |
6 |     foo(1, 2.);
  |     --- -  ^^ expected integer, found floating-point number
  |     |   |
  |     |   expected argument `b` to be an integer because that argument needs to match the type of this parameter
  |     arguments to this function are incorrect
  |
note: function defined here
 --> generic-mismatch-reporting-issue-116615.rs:1:4
  |
1 | fn foo<T>(a: T, b: T) {}
  |    ^^^ -  ----  ----
  |        |  |     |
  |        |  |     this parameter needs to match the integer type of `a`
  |        |  `b` needs to match the type of this parameter
  |        `a` and `b` all reference this parameter T
```

Open question, do we need to worry about error message translation into other languages? Not sure what the status of that is in Rust.

NB: Needs some checking over and some tests have altered that need sanity checking, but overall this is starting to get somewhere now. Will take out of draft PR status when this has been done, raising now to allow feedback at this stage, probably 90% ready.
This commit is contained in:
Matthias Krüger 2024-04-03 22:10:59 +02:00 committed by GitHub
commit 32c8c5cb7e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 505 additions and 38 deletions

View File

@ -1951,6 +1951,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,

View File

@ -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};
@ -818,6 +819,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);
@ -904,6 +907,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()
{
@ -932,6 +944,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);
@ -1270,6 +1284,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
@ -1317,7 +1340,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 {
@ -2094,6 +2127,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 {
@ -2185,21 +2220,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())
.and_then(|node| node.generics())
.into_iter()
.flat_map(|id| self.tcx.hir().body(id).params)
.skip(if is_method { 1 } else { 0 });
for (_, param) in params
.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)));
@ -2260,6 +2438,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> {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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`.