mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
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:
commit
32c8c5cb7e
@ -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,
|
||||
|
@ -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(¶m_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> {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
@ -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`.
|
Loading…
Reference in New Issue
Block a user