Added ability to report on generic argument mismatch better

Needs some checking over and some tests have altered that need sanity checking, but overall this is starting to get somewhere now.
This commit is contained in:
Steven Trotter 2024-02-25 16:36:26 +00:00
parent ee03c286cf
commit df93364057
17 changed files with 611 additions and 75 deletions

View File

@ -50,7 +50,7 @@ pub use rustc_error_messages::{
fallback_fluent_bundle, fluent_bundle, DelayDm, DiagMessage, FluentBundle, LanguageIdentifier, fallback_fluent_bundle, fluent_bundle, DelayDm, DiagMessage, FluentBundle, LanguageIdentifier,
LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
}; };
pub use rustc_lint_defs::{pluralize, Applicability}; pub use rustc_lint_defs::{a_or_an, display_list_with_comma_and, pluralize, Applicability};
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
pub use rustc_span::ErrorGuaranteed; pub use rustc_span::ErrorGuaranteed;
pub use snippet::Style; pub use snippet::Style;

View File

@ -17,7 +17,8 @@ use itertools::Itertools;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{ use rustc_errors::{
codes::*, pluralize, Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, codes::*, display_list_with_comma_and, pluralize, Applicability, Diag,
DiagnosticBuilder, ErrorGuaranteed, MultiSpan, StashKey,
}; };
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def::{CtorOf, DefKind, Res};
@ -423,11 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"expected formal_input_tys to be the same size as expected_input_tys" "expected formal_input_tys to be the same size as expected_input_tys"
); );
let formal_and_expected_inputs = IndexVec::from_iter( let formal_and_expected_inputs = IndexVec::from_iter(
formal_input_tys formal_input_tys.iter().copied().zip_eq(expected_input_tys.iter().copied()),
.iter()
.copied()
.zip_eq(expected_input_tys.iter().copied())
.map(|vars| self.resolve_vars_if_possible(vars)),
); );
self.set_tainted_by_errors(self.report_arg_errors( self.set_tainted_by_errors(self.report_arg_errors(
@ -642,6 +639,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx]; let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx];
let formal_input_ty = self.resolve_vars_if_possible(formal_input_ty);
let expected_input_ty = self.resolve_vars_if_possible(expected_input_ty);
// If either is an error type, we defy the usual convention and consider them to *not* be // If either is an error type, we defy the usual convention and consider them to *not* be
// coercible. This prevents our error message heuristic from trying to pass errors into // coercible. This prevents our error message heuristic from trying to pass errors into
// every argument. // every argument.
@ -714,7 +713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Do we have as many extra provided arguments as the tuple's length? // Do we have as many extra provided arguments as the tuple's length?
// If so, we might have just forgotten to wrap some args in a tuple. // If so, we might have just forgotten to wrap some args in a tuple.
if let Some(ty::Tuple(tys)) = if let Some(ty::Tuple(tys)) =
formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind()) formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| self.resolve_vars_if_possible(tys.1).kind())
// If the tuple is unit, we're not actually wrapping any arguments. // If the tuple is unit, we're not actually wrapping any arguments.
&& !tys.is_empty() && !tys.is_empty()
&& provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
@ -733,7 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()),
), ),
) { ) {
if !self.can_coerce(provided_ty, *expected_ty) { if !self.can_coerce(provided_ty, self.resolve_vars_if_possible(*expected_ty)) {
satisfied = false; satisfied = false;
break; break;
} }
@ -752,10 +751,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if tys.len() == 1 { if tys.len() == 1 {
// A tuple wrap suggestion actually occurs within, // A tuple wrap suggestion actually occurs within,
// so don't do anything special here. // so don't do anything special here.
let (formal_ty, expected_ty) =
formal_and_expected_inputs[mismatch_idx.into()];
let formal_ty = self.resolve_vars_if_possible(formal_ty);
let expected_ty = self.resolve_vars_if_possible(expected_ty);
err = self.err_ctxt().report_and_explain_type_error( err = self.err_ctxt().report_and_explain_type_error(
mk_trace( mk_trace(
*lo, *lo,
formal_and_expected_inputs[mismatch_idx.into()], (formal_ty, expected_ty),
provided_arg_tys[mismatch_idx.into()].0, provided_arg_tys[mismatch_idx.into()].0,
), ),
terr, terr,
@ -795,6 +798,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr, call_expr,
None, None,
Some(mismatch_idx), Some(mismatch_idx),
&matched_inputs,
&formal_and_expected_inputs,
is_method, is_method,
); );
suggest_confusable(&mut err); suggest_confusable(&mut err);
@ -837,8 +842,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return true; return true;
}; };
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
let trace = let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); let formal_ty = self.resolve_vars_if_possible(formal_ty);
let expected_ty = self.resolve_vars_if_possible(expected_ty);
let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) { if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
let mut err = self.err_ctxt().report_and_explain_type_error(trace, *e); let mut err = self.err_ctxt().report_and_explain_type_error(trace, *e);
suggest_confusable(&mut err); suggest_confusable(&mut err);
@ -866,6 +873,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
] = &errors[..] ] = &errors[..]
{ {
let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
let formal_ty = self.resolve_vars_if_possible(formal_ty);
let expected_ty = self.resolve_vars_if_possible(expected_ty);
let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err); let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
@ -881,6 +890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect")); 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,
);
if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind
&& provided_idx.as_usize() == expected_idx.as_usize() && provided_idx.as_usize() == expected_idx.as_usize()
{ {
@ -909,6 +926,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr, call_expr,
Some(expected_ty), Some(expected_ty),
Some(expected_idx.as_usize()), Some(expected_idx.as_usize()),
&matched_inputs,
&formal_and_expected_inputs,
is_method, is_method,
); );
suggest_confusable(&mut err); suggest_confusable(&mut err);
@ -984,6 +1003,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match error { match error {
Error::Invalid(provided_idx, expected_idx, compatibility) => { Error::Invalid(provided_idx, expected_idx, compatibility) => {
let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
let formal_ty = self.resolve_vars_if_possible(formal_ty);
let expected_ty = self.resolve_vars_if_possible(expected_ty);
let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; let (provided_ty, provided_span) = provided_arg_tys[provided_idx];
if let Compatibility::Incompatible(error) = compatibility { if let Compatibility::Incompatible(error) = compatibility {
let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
@ -1088,6 +1109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &missing_idxs[..] { match &missing_idxs[..] {
&[expected_idx] => { &[expected_idx] => {
let (_, input_ty) = formal_and_expected_inputs[expected_idx]; let (_, input_ty) = formal_and_expected_inputs[expected_idx];
let input_ty = self.resolve_vars_if_possible(input_ty);
let span = if let Some((_, arg_span)) = let span = if let Some((_, arg_span)) =
provided_arg_tys.get(expected_idx.to_provided_idx()) provided_arg_tys.get(expected_idx.to_provided_idx())
{ {
@ -1110,6 +1132,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&[first_idx, second_idx] => { &[first_idx, second_idx] => {
let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; let (_, first_expected_ty) = formal_and_expected_inputs[first_idx];
let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; let (_, second_expected_ty) = formal_and_expected_inputs[second_idx];
let first_expected_ty =
self.resolve_vars_if_possible(first_expected_ty);
let second_expected_ty =
self.resolve_vars_if_possible(second_expected_ty);
let span = if let (Some((_, first_span)), Some((_, second_span))) = ( let span = if let (Some((_, first_span)), Some((_, second_span))) = (
provided_arg_tys.get(first_idx.to_provided_idx()), provided_arg_tys.get(first_idx.to_provided_idx()),
provided_arg_tys.get(second_idx.to_provided_idx()), provided_arg_tys.get(second_idx.to_provided_idx()),
@ -1136,8 +1162,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
&[first_idx, second_idx, third_idx] => { &[first_idx, second_idx, third_idx] => {
let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; let (_, first_expected_ty) = formal_and_expected_inputs[first_idx];
let first_expected_ty =
self.resolve_vars_if_possible(first_expected_ty);
let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; let (_, second_expected_ty) = formal_and_expected_inputs[second_idx];
let second_expected_ty =
self.resolve_vars_if_possible(second_expected_ty);
let (_, third_expected_ty) = formal_and_expected_inputs[third_idx]; let (_, third_expected_ty) = formal_and_expected_inputs[third_idx];
let third_expected_ty =
self.resolve_vars_if_possible(third_expected_ty);
let span = if let (Some((_, first_span)), Some((_, third_span))) = ( let span = if let (Some((_, first_span)), Some((_, third_span))) = (
provided_arg_tys.get(first_idx.to_provided_idx()), provided_arg_tys.get(first_idx.to_provided_idx()),
provided_arg_tys.get(third_idx.to_provided_idx()), provided_arg_tys.get(third_idx.to_provided_idx()),
@ -1197,6 +1229,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) => { ) => {
let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx];
let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx];
let first_expected_ty = self.resolve_vars_if_possible(first_expected_ty);
let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) {
format!(", found `{first_provided_ty}`") format!(", found `{first_provided_ty}`")
} else { } else {
@ -1209,6 +1242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx];
let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx];
let second_provided_ty = self.resolve_vars_if_possible(second_provided_ty);
let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) {
format!(", found `{second_provided_ty}`") format!(", found `{second_provided_ty}`")
} else { } else {
@ -1227,6 +1261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Error::Permutation(args) => { Error::Permutation(args) => {
for (dst_arg, dest_input) in args { for (dst_arg, dest_input) in args {
let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; let (_, expected_ty) = formal_and_expected_inputs[dst_arg];
let expected_ty = self.resolve_vars_if_possible(expected_ty);
let (provided_ty, provided_span) = provided_arg_tys[dest_input]; let (provided_ty, provided_span) = provided_arg_tys[dest_input];
let provided_ty_name = if !has_error_or_infer([provided_ty]) { let provided_ty_name = if !has_error_or_infer([provided_ty]) {
format!(", found `{provided_ty}`") format!(", found `{provided_ty}`")
@ -1247,6 +1282,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
self.label_generic_mismatches(
&mut err,
fn_def_id,
&matched_inputs,
&provided_arg_tys,
&formal_and_expected_inputs,
);
// Incorporate the argument changes in the removal suggestion. // 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 // 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 // multipart suggestion, but in order to do so we need to figure out *where* the arg that
@ -1282,6 +1325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// To suggest a multipart suggestion when encountering `foo(1, "")` where the def // To suggest a multipart suggestion when encountering `foo(1, "")` where the def
// was `fn foo(())`. // was `fn foo(())`.
let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
let expected_ty = self.resolve_vars_if_possible(expected_ty);
suggestions.push((*arg_span, ty_to_snippet(expected_ty, expected_idx))); suggestions.push((*arg_span, ty_to_snippet(expected_ty, expected_idx)));
} }
} }
@ -1294,7 +1338,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
// Call out where the function is defined // 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 // And add a suggestion block for all of the parameters
let suggestion_text = match suggestion_text { let suggestion_text = match suggestion_text {
@ -1348,6 +1402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else { } else {
// Propose a placeholder of the correct type // Propose a placeholder of the correct type
let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
let expected_ty = self.resolve_vars_if_possible(expected_ty);
ty_to_snippet(expected_ty, expected_idx) ty_to_snippet(expected_ty, expected_idx)
}; };
suggestion += &suggestion_text; suggestion += &suggestion_text;
@ -2054,6 +2109,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty: Option<Ty<'tcx>>, expected_ty: Option<Ty<'tcx>>,
// A specific argument should be labeled, instead of all of them // A specific argument should be labeled, instead of all of them
expected_idx: Option<usize>, expected_idx: Option<usize>,
matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
is_method: bool, is_method: bool,
) { ) {
let Some(mut def_id) = callable_def_id else { let Some(mut def_id) = callable_def_id else {
@ -2145,21 +2202,200 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{ {
let mut spans: MultiSpan = def_span.into(); let mut spans: MultiSpan = def_span.into();
let params = self let param_generics: Vec<Option<&hir::GenericParam<'_>>> = self
.tcx
.hir()
.get_if_local(def_id)
.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
{
self.tcx
.hir()
.get_if_local(def_id)
.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<'_>> = self
.tcx .tcx
.hir() .hir()
.get_if_local(def_id) .get_if_local(def_id)
.and_then(|node| node.body_id()) .and_then(|node| node.body_id())
.into_iter() .into_iter()
.flat_map(|id| self.tcx.hir().body(id).params) .flat_map(|id| self.tcx.hir().body(id).params)
.skip(if is_method { 1 } else { 0 }); .skip(if is_method { 1 } else { 0 })
.collect();
for (_, param) in params if params.len() == param_generics.len() {
.into_iter() let mut generics_map: Vec<(usize, &hir::GenericParam<'_>)> = Vec::new();
.enumerate() // This is a map from the index of the generic to the index of the parameter and the
.filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx)) // parameter
let mut matched_params_map: Vec<(usize, usize, &hir::Param<'_>)> = Vec::new();
let mut unmatched_params_map: Vec<(usize, &hir::Param<'_>)> = Vec::new();
for (idx, (param, generic)) in
params.iter().zip_eq(param_generics.iter()).enumerate()
{ {
if matched_inputs[idx.into()].is_none() {
spans.push_span_label(param.span, ""); spans.push_span_label(param.span, "");
continue;
}
let Some(generic) = generic else {
spans.push_span_label(param.span, "");
continue;
};
let mut found_unmatched_generic_params = vec![];
for unmatching_idx in idx + 1..params.len() {
if matched_inputs[unmatching_idx.into()].is_none()
&& let Some(unmatched_idx_param_generic) =
param_generics[unmatching_idx]
&& unmatched_idx_param_generic.name.ident() == generic.name.ident()
{
found_unmatched_generic_params.push(params[unmatching_idx]);
}
}
if found_unmatched_generic_params.is_empty() {
continue;
}
let generics_idx = generics_map
.iter()
.filter(|x| x.1.name.ident() == generic.name.ident())
.next()
.map(|x| x.0);
let generics_idx = generics_idx.unwrap_or_else(|| {
let generics_map_len = generics_map.len();
generics_map.push((generics_map_len, generic));
generics_map_len
});
matched_params_map.push((generics_idx, idx, param));
if unmatched_params_map.iter().filter(|x| x.0 == generics_idx).count() > 0 {
// Already processed the unmatched params
continue;
}
for unmatched_param in &found_unmatched_generic_params {
unmatched_params_map.push((generics_idx, unmatched_param));
}
}
for (generic_idx, generic) in &generics_map {
let matched_params: Vec<(usize, &hir::Param<'_>)> = matched_params_map
.iter()
.filter(|x| x.0 == *generic_idx)
.map(|x| (x.1, x.2))
.collect();
let unmatched_params: Vec<&hir::Param<'_>> = unmatched_params_map
.iter()
.filter(|x| x.0 == *generic_idx)
.map(|x| x.1)
.collect();
let all_param_idents: Vec<String> = matched_params
.iter()
.map(|x| &x.1)
.chain(unmatched_params.iter())
.map(|x| {
if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind {
format!("`{ident}`")
} else {
"{unknown}".to_string()
}
})
.collect();
spans.push_span_label(
generic.span,
format!(
"{} all reference this parameter {}",
display_list_with_comma_and(&all_param_idents),
generic.name.ident().name,
),
);
for unmatched_param in &unmatched_params {
let idents: Vec<String> = matched_params
.iter()
.map(|x| {
if let hir::PatKind::Binding(_, _, ident, _) = x.1.pat.kind {
format!("`{ident}`")
} else {
"{unknown}".to_string()
}
})
.collect();
let matched_ty = matched_params
.iter()
.next()
.map(|x| formal_and_expected_inputs[x.0.into()]);
if let Some(matched_ty) = matched_ty {
let matched_ty =
self.resolve_vars_if_possible(matched_ty.0).sort_string(self.tcx);
spans.push_span_label(
unmatched_param.span,
format!(
"this parameter needs to match the {} type of {}",
matched_ty,
display_list_with_comma_and(&idents)
),
);
} else {
spans.push_span_label(
unmatched_param.span,
format!(
"this parameter needs to match the type of {}",
display_list_with_comma_and(&idents)
),
);
}
}
for matched_param in &matched_params {
let idents: Vec<String> = unmatched_params
.iter()
.map(|x| {
if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind {
format!("`{ident}`")
} else {
"{unknown}".to_string()
}
})
.collect();
spans.push_span_label(
matched_param.1.span,
format!(
"{} needs to match the type of this parameter",
display_list_with_comma_and(&idents)
),
);
}
}
} else {
for (_, param) in params.iter().enumerate().filter(|(idx, _)| {
expected_idx.map_or(true, |expected_idx| expected_idx == *idx)
}) {
spans.push_span_label(param.span, "");
}
} }
err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
@ -2225,6 +2461,118 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
} }
} }
fn label_generic_mismatches(
&self,
err: &mut DiagnosticBuilder<'_>,
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>)>,
) {
let Some(def_id) = callable_def_id else {
return;
};
for (matched_idx, matched_arg) in matched_inputs.iter_enumerated() {
let Some(matched_input) = matched_arg else {
continue;
};
let (_, matched_arg_span) = provided_arg_tys[*matched_input];
let (matched_formal_ty, _) = formal_and_expected_inputs[matched_idx];
let ty::Infer(ty::TyVar(a)) = matched_formal_ty.kind() else {
continue;
};
let mut formal_ty_idxs_matched: Vec<usize> = vec![];
let mut expected_ty_matched = None;
for (input_idx, (formal_ty, expected_ty)) in formal_and_expected_inputs
.iter_enumerated()
// Only care about args after the matched one we're checking.
//
// NB: Incompatible should always come after their matching generics.
// e.g. if we have a function fn f(a: T, b: T, c: T) and we call it with
// f(1, 2, 3.0) then the first will force T to be an integer, the second
// then matches and the third is the incompatible argument.
.filter(|(idx, _)| *idx > matched_idx)
{
if let ty::Infer(ty::TyVar(b)) = formal_ty.kind() {
if self.root_var(*a) == self.root_var(*b) {
formal_ty_idxs_matched.push(input_idx.into());
if expected_ty_matched.is_none() {
expected_ty_matched = Some(expected_ty);
}
}
}
}
let Some(expected_ty) = expected_ty_matched else {
continue;
};
let params = 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);
let mut all_pats_matched: Vec<String> = vec![];
let mut incompatible_pats_matched: Vec<String> = vec![];
for (idx, param) in params
.into_iter()
.enumerate()
.filter(|(idx, _)| formal_ty_idxs_matched.contains(idx))
{
let ident = if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind {
format!("`{ident}`")
} else {
format!("`idx:{idx}`")
};
if matched_inputs[idx.into()].is_none() {
incompatible_pats_matched.push(ident.clone());
}
all_pats_matched.push(ident);
}
let expected_display_type =
self.resolve_vars_if_possible(*expected_ty).sort_string(self.tcx);
let label = if all_pats_matched.len() == 0 {
format!(
"expected all arguments to be {} because they need to match the type of this parameter",
expected_display_type
)
} else if all_pats_matched.len() == incompatible_pats_matched.len() {
format!(
"expected {} {} to be {} {} because {} to match the type of this parameter",
format!("argument{}", pluralize!(incompatible_pats_matched.len())),
display_list_with_comma_and(&incompatible_pats_matched),
a_or_an(&expected_display_type),
expected_display_type,
if all_pats_matched.len() == 1 {
"that argument needs"
} else {
"those arguments need"
}
)
} else {
format!(
"expected {} {} to be {} {} because the {} {} {} to match the type of this parameter",
format!("argument{}", pluralize!(incompatible_pats_matched.len())),
display_list_with_comma_and(&incompatible_pats_matched),
a_or_an(&expected_display_type),
expected_display_type,
format!("argument{}", pluralize!(all_pats_matched.len())),
display_list_with_comma_and(&all_pats_matched),
format!("need{}", pluralize!(if all_pats_matched.len() == 1 { 0 } else { 1 })),
)
};
err.span_label(matched_arg_span, label);
}
}
} }
struct FindClosureArg<'tcx> { struct FindClosureArg<'tcx> {

View File

@ -39,6 +39,39 @@ macro_rules! pluralize {
}; };
} }
/// 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..])),
}
}
/// Indicates the confidence in the correctness of a suggestion. /// Indicates the confidence in the correctness of a suggestion.
/// ///
/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion

View File

@ -45,7 +45,7 @@ note: function defined here
--> $DIR/extra_arguments.rs:2:4 --> $DIR/extra_arguments.rs:2:4
| |
LL | fn one_arg<T>(_a: T) {} LL | fn one_arg<T>(_a: T) {}
| ^^^^^^^ ----- | ^^^^^^^
error[E0061]: this function takes 1 argument but 2 arguments were supplied error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/extra_arguments.rs:23:3 --> $DIR/extra_arguments.rs:23:3
@ -60,7 +60,7 @@ note: function defined here
--> $DIR/extra_arguments.rs:2:4 --> $DIR/extra_arguments.rs:2:4
| |
LL | fn one_arg<T>(_a: T) {} LL | fn one_arg<T>(_a: T) {}
| ^^^^^^^ ----- | ^^^^^^^
error[E0061]: this function takes 1 argument but 3 arguments were supplied error[E0061]: this function takes 1 argument but 3 arguments were supplied
--> $DIR/extra_arguments.rs:24:3 --> $DIR/extra_arguments.rs:24:3
@ -74,7 +74,7 @@ note: function defined here
--> $DIR/extra_arguments.rs:2:4 --> $DIR/extra_arguments.rs:2:4
| |
LL | fn one_arg<T>(_a: T) {} LL | fn one_arg<T>(_a: T) {}
| ^^^^^^^ ----- | ^^^^^^^
help: remove the extra arguments help: remove the extra arguments
| |
LL - one_arg(1, "", 1.0); LL - one_arg(1, "", 1.0);
@ -319,7 +319,7 @@ note: function defined here
--> $DIR/extra_arguments.rs:2:4 --> $DIR/extra_arguments.rs:2:4
| |
LL | fn one_arg<T>(_a: T) {} LL | fn one_arg<T>(_a: T) {}
| ^^^^^^^ ----- | ^^^^^^^
error[E0061]: this function takes 1 argument but 2 arguments were supplied error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/extra_arguments.rs:54:3 --> $DIR/extra_arguments.rs:54:3
@ -334,7 +334,7 @@ note: function defined here
--> $DIR/extra_arguments.rs:2:4 --> $DIR/extra_arguments.rs:2:4
| |
LL | fn one_arg<T>(_a: T) {} LL | fn one_arg<T>(_a: T) {}
| ^^^^^^^ ----- | ^^^^^^^
error[E0061]: this function takes 1 argument but 2 arguments were supplied error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/extra_arguments.rs:55:3 --> $DIR/extra_arguments.rs:55:3
@ -349,7 +349,7 @@ note: function defined here
--> $DIR/extra_arguments.rs:2:4 --> $DIR/extra_arguments.rs:2:4
| |
LL | fn one_arg<T>(_a: T) {} LL | fn one_arg<T>(_a: T) {}
| ^^^^^^^ ----- | ^^^^^^^
error[E0061]: this function takes 1 argument but 2 arguments were supplied error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/extra_arguments.rs:60:3 --> $DIR/extra_arguments.rs:60:3
@ -364,7 +364,7 @@ note: function defined here
--> $DIR/extra_arguments.rs:2:4 --> $DIR/extra_arguments.rs:2:4
| |
LL | fn one_arg<T>(_a: T) {} LL | fn one_arg<T>(_a: T) {}
| ^^^^^^^ ----- | ^^^^^^^
error: aborting due to 22 previous errors error: aborting due to 22 previous errors

View File

@ -24,7 +24,7 @@ note: function defined here
--> $DIR/invalid_arguments.rs:6:4 --> $DIR/invalid_arguments.rs:6:4
| |
LL | fn two_arg_same(_a: i32, _b: i32) {} LL | fn two_arg_same(_a: i32, _b: i32) {}
| ^^^^^^^^^^^^ ------- | ^^^^^^^^^^^^ ------- -------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/invalid_arguments.rs:17:16 --> $DIR/invalid_arguments.rs:17:16
@ -38,7 +38,7 @@ note: function defined here
--> $DIR/invalid_arguments.rs:6:4 --> $DIR/invalid_arguments.rs:6:4
| |
LL | fn two_arg_same(_a: i32, _b: i32) {} LL | fn two_arg_same(_a: i32, _b: i32) {}
| ^^^^^^^^^^^^ ------- | ^^^^^^^^^^^^ ------- -------
error[E0308]: arguments to this function are incorrect error[E0308]: arguments to this function are incorrect
--> $DIR/invalid_arguments.rs:18:3 --> $DIR/invalid_arguments.rs:18:3
@ -66,7 +66,7 @@ note: function defined here
--> $DIR/invalid_arguments.rs:7:4 --> $DIR/invalid_arguments.rs:7:4
| |
LL | fn two_arg_diff(_a: i32, _b: f32) {} LL | fn two_arg_diff(_a: i32, _b: f32) {}
| ^^^^^^^^^^^^ ------- | ^^^^^^^^^^^^ ------- -------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/invalid_arguments.rs:20:16 --> $DIR/invalid_arguments.rs:20:16
@ -80,7 +80,7 @@ note: function defined here
--> $DIR/invalid_arguments.rs:7:4 --> $DIR/invalid_arguments.rs:7:4
| |
LL | fn two_arg_diff(_a: i32, _b: f32) {} LL | fn two_arg_diff(_a: i32, _b: f32) {}
| ^^^^^^^^^^^^ ------- | ^^^^^^^^^^^^ ------- -------
error[E0308]: arguments to this function are incorrect error[E0308]: arguments to this function are incorrect
--> $DIR/invalid_arguments.rs:21:3 --> $DIR/invalid_arguments.rs:21:3
@ -108,7 +108,7 @@ note: function defined here
--> $DIR/invalid_arguments.rs:8:4 --> $DIR/invalid_arguments.rs:8:4
| |
LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {} LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {}
| ^^^^^^^^^^^^^^ ------- | ^^^^^^^^^^^^^^ ------- ------- --------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/invalid_arguments.rs:25:21 --> $DIR/invalid_arguments.rs:25:21
@ -122,7 +122,7 @@ note: function defined here
--> $DIR/invalid_arguments.rs:8:4 --> $DIR/invalid_arguments.rs:8:4
| |
LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {} LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {}
| ^^^^^^^^^^^^^^ ------- | ^^^^^^^^^^^^^^ ------- ------- --------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/invalid_arguments.rs:26:26 --> $DIR/invalid_arguments.rs:26:26
@ -136,7 +136,7 @@ note: function defined here
--> $DIR/invalid_arguments.rs:8:4 --> $DIR/invalid_arguments.rs:8:4
| |
LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {} LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {}
| ^^^^^^^^^^^^^^ -------- | ^^^^^^^^^^^^^^ ------- ------- --------
error[E0308]: arguments to this function are incorrect error[E0308]: arguments to this function are incorrect
--> $DIR/invalid_arguments.rs:28:3 --> $DIR/invalid_arguments.rs:28:3
@ -207,7 +207,7 @@ note: function defined here
--> $DIR/invalid_arguments.rs:9:4 --> $DIR/invalid_arguments.rs:9:4
| |
LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {} LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {}
| ^^^^^^^^^^^^^^^^ ------- | ^^^^^^^^^^^^^^^^ ------- ------- --------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/invalid_arguments.rs:35:23 --> $DIR/invalid_arguments.rs:35:23
@ -221,7 +221,7 @@ note: function defined here
--> $DIR/invalid_arguments.rs:9:4 --> $DIR/invalid_arguments.rs:9:4
| |
LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {} LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {}
| ^^^^^^^^^^^^^^^^ ------- | ^^^^^^^^^^^^^^^^ ------- ------- --------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/invalid_arguments.rs:36:26 --> $DIR/invalid_arguments.rs:36:26
@ -235,7 +235,7 @@ note: function defined here
--> $DIR/invalid_arguments.rs:9:4 --> $DIR/invalid_arguments.rs:9:4
| |
LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {} LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {}
| ^^^^^^^^^^^^^^^^ -------- | ^^^^^^^^^^^^^^^^ ------- ------- --------
error[E0308]: arguments to this function are incorrect error[E0308]: arguments to this function are incorrect
--> $DIR/invalid_arguments.rs:38:3 --> $DIR/invalid_arguments.rs:38:3

View File

@ -11,9 +11,31 @@ note: method defined here
| |
LL | fn foo( LL | fn foo(
| ^^^ | ^^^
... LL | &self,
LL | a: i32,
| ------
LL | b: i32,
| ------
LL | c: i32,
| ------
LL | d: i32,
| ------
LL | e: i32,
| ------
LL | f: i32, LL | f: i32,
| ------ | ------
LL | g: i32,
| ------
LL | h: i32,
| ------
LL | i: i32,
| ------
LL | j: i32,
| ------
LL | k: i32,
| ------
LL | l: i32,
| ------
help: consider dereferencing the borrow help: consider dereferencing the borrow
| |
LL | qux.foo(a, b, c, d, e, *f, g, h, i, j, k, l); LL | qux.foo(a, b, c, d, e, *f, g, h, i, j, k, l);

View File

@ -5,6 +5,7 @@ LL | fun(async {}, async {});
| --- -------- ^^^^^^^^ expected `async` block, found a different `async` block | --- -------- ^^^^^^^^ expected `async` block, found a different `async` block
| | | | | |
| | the expected `async` block | | the expected `async` block
| | expected argument `f2` to be an `async` block because that argument needs to match the type of this parameter
| arguments to this function are incorrect | arguments to this function are incorrect
| |
= note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}` = note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}`
@ -13,14 +14,19 @@ note: function defined here
--> $DIR/coroutine-desc.rs:8:4 --> $DIR/coroutine-desc.rs:8:4
| |
LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {} 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 type of this parameter
| `f1` and `f2` all reference this parameter F
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/coroutine-desc.rs:12:16 --> $DIR/coroutine-desc.rs:12:16
| |
LL | fun(one(), two()); LL | fun(one(), two());
| --- ^^^^^ expected future, found a different future | --- ----- ^^^^^ expected future, found a different future
| | | | |
| | expected argument `f2` to be a future because that argument needs to match the type of this parameter
| arguments to this function are incorrect | arguments to this function are incorrect
| |
= help: consider `await`ing on both `Future`s = help: consider `await`ing on both `Future`s
@ -29,15 +35,20 @@ note: function defined here
--> $DIR/coroutine-desc.rs:8:4 --> $DIR/coroutine-desc.rs:8:4
| |
LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {} 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 type of this parameter
| `f1` and `f2` all reference this parameter F
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/coroutine-desc.rs:14:26 --> $DIR/coroutine-desc.rs:14:26
| |
LL | fun((async || {})(), (async || {})()); LL | fun((async || {})(), (async || {})());
| --- -- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body | --- --------------- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
| | | | | | |
| | the expected `async` closure body | | | the expected `async` closure body
| | expected argument `f2` to be an `async` closure body because that argument needs to match the type of this parameter
| arguments to this function are incorrect | arguments to this function are incorrect
| |
= note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}` = note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}`
@ -46,7 +57,11 @@ note: function defined here
--> $DIR/coroutine-desc.rs:8:4 --> $DIR/coroutine-desc.rs:8:4
| |
LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {} 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 type of this parameter
| `f1` and `f2` all reference this parameter F
error: aborting due to 3 previous errors 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 --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18
| |
LL | test(&mut 7, &7); LL | test(&mut 7, &7);
| ---- ^^ types differ in mutability | ---- ------ ^^ types differ in mutability
| | | | |
| | expected argument `_b` to be an `&mut {integer}` because that argument needs to match the type of this parameter
| arguments to this function are incorrect | arguments to this function are incorrect
| |
= note: expected mutable reference `&mut {integer}` = note: expected mutable reference `&mut {integer}`
@ -12,7 +13,11 @@ note: function defined here
--> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4 --> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4
| |
LL | fn test<T>(_a: T, _b: T) {} LL | fn test<T>(_a: T, _b: T) {}
| ^^^^ ----- | ^^^^ - ----- -----
| | | |
| | | this parameter needs to match the `&mut {integer}` type of `_a`
| | `_b` needs to match the type of this parameter
| `_a` and `_b` all reference this parameter T
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -12,7 +12,7 @@ note: function defined here
--> $DIR/coerce-to-bang.rs:3:4 --> $DIR/coerce-to-bang.rs:3:4
| |
LL | fn foo(x: usize, y: !, z: usize) { } LL | fn foo(x: usize, y: !, z: usize) { }
| ^^^ ---- | ^^^ -------- ---- --------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/coerce-to-bang.rs:18:13 --> $DIR/coerce-to-bang.rs:18:13
@ -28,7 +28,7 @@ note: function defined here
--> $DIR/coerce-to-bang.rs:3:4 --> $DIR/coerce-to-bang.rs:3:4
| |
LL | fn foo(x: usize, y: !, z: usize) { } LL | fn foo(x: usize, y: !, z: usize) { }
| ^^^ ---- | ^^^ -------- ---- --------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/coerce-to-bang.rs:26:12 --> $DIR/coerce-to-bang.rs:26:12
@ -44,7 +44,7 @@ note: function defined here
--> $DIR/coerce-to-bang.rs:3:4 --> $DIR/coerce-to-bang.rs:3:4
| |
LL | fn foo(x: usize, y: !, z: usize) { } LL | fn foo(x: usize, y: !, z: usize) { }
| ^^^ ---- | ^^^ -------- ---- --------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/coerce-to-bang.rs:36:12 --> $DIR/coerce-to-bang.rs:36:12
@ -60,7 +60,7 @@ note: function defined here
--> $DIR/coerce-to-bang.rs:3:4 --> $DIR/coerce-to-bang.rs:3:4
| |
LL | fn foo(x: usize, y: !, z: usize) { } LL | fn foo(x: usize, y: !, z: usize) { }
| ^^^ ---- | ^^^ -------- ---- --------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/coerce-to-bang.rs:45:12 --> $DIR/coerce-to-bang.rs:45:12
@ -76,7 +76,7 @@ note: function defined here
--> $DIR/coerce-to-bang.rs:3:4 --> $DIR/coerce-to-bang.rs:3:4
| |
LL | fn foo(x: usize, y: !, z: usize) { } LL | fn foo(x: usize, y: !, z: usize) { }
| ^^^ ---- | ^^^ -------- ---- --------
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/coerce-to-bang.rs:50:21 --> $DIR/coerce-to-bang.rs:50:21

View File

@ -2,8 +2,9 @@ error[E0308]: mismatched types
--> $DIR/fn-item-type.rs:22:19 --> $DIR/fn-item-type.rs:22:19
| |
LL | eq(foo::<u8>, bar::<u8>); LL | eq(foo::<u8>, bar::<u8>);
| -- ^^^^^^^^^ expected fn item, found a different fn item | -- --------- ^^^^^^^^^ expected fn item, found a different fn item
| | | | |
| | expected argument `y` to be a fn item because that argument needs to match the type of this parameter
| arguments to this function are incorrect | arguments to this function are incorrect
| |
= note: expected fn item `fn(_) -> _ {foo::<u8>}` = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@ -13,15 +14,20 @@ note: function defined here
--> $DIR/fn-item-type.rs:11:4 --> $DIR/fn-item-type.rs:11:4
| |
LL | fn eq<T>(x: T, y: T) {} LL | fn eq<T>(x: T, y: T) {}
| ^^ ---- | ^^ - ---- ----
| | | |
| | | this parameter needs to match the fn item type of `x`
| | `y` needs to match the 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` = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/fn-item-type.rs:29:19 --> $DIR/fn-item-type.rs:29:19
| |
LL | eq(foo::<u8>, foo::<i8>); LL | eq(foo::<u8>, foo::<i8>);
| -- ^^^^^^^^^ expected `u8`, found `i8` | -- --------- ^^^^^^^^^ expected `u8`, found `i8`
| | | | |
| | expected argument `y` to be a fn item because that argument needs to match the type of this parameter
| arguments to this function are incorrect | arguments to this function are incorrect
| |
= note: expected fn item `fn(_) -> _ {foo::<u8>}` = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@ -31,15 +37,20 @@ note: function defined here
--> $DIR/fn-item-type.rs:11:4 --> $DIR/fn-item-type.rs:11:4
| |
LL | fn eq<T>(x: T, y: T) {} LL | fn eq<T>(x: T, y: T) {}
| ^^ ---- | ^^ - ---- ----
| | | |
| | | this parameter needs to match the fn item type of `x`
| | `y` needs to match the 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` = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/fn-item-type.rs:34:23 --> $DIR/fn-item-type.rs:34:23
| |
LL | eq(bar::<String>, bar::<Vec<u8>>); LL | eq(bar::<String>, bar::<Vec<u8>>);
| -- ^^^^^^^^^^^^^^ expected `String`, found `Vec<u8>` | -- ------------- ^^^^^^^^^^^^^^ expected `String`, found `Vec<u8>`
| | | | |
| | expected argument `y` to be a fn item because that argument needs to match the type of this parameter
| arguments to this function are incorrect | arguments to this function are incorrect
| |
= note: expected fn item `fn(_) -> _ {bar::<String>}` = note: expected fn item `fn(_) -> _ {bar::<String>}`
@ -49,15 +60,20 @@ note: function defined here
--> $DIR/fn-item-type.rs:11:4 --> $DIR/fn-item-type.rs:11:4
| |
LL | fn eq<T>(x: T, y: T) {} LL | fn eq<T>(x: T, y: T) {}
| ^^ ---- | ^^ - ---- ----
| | | |
| | | this parameter needs to match the fn item type of `x`
| | `y` needs to match the 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` = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/fn-item-type.rs:40:26 --> $DIR/fn-item-type.rs:40:26
| |
LL | eq(<u8 as Foo>::foo, <u16 as Foo>::foo); LL | eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
| -- ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16` | -- ---------------- ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
| | | | |
| | expected argument `y` to be a fn item because that argument needs to match the type of this parameter
| arguments to this function are incorrect | arguments to this function are incorrect
| |
= note: expected fn item `fn() {<u8 as Foo>::foo}` = note: expected fn item `fn() {<u8 as Foo>::foo}`
@ -67,15 +83,20 @@ note: function defined here
--> $DIR/fn-item-type.rs:11:4 --> $DIR/fn-item-type.rs:11:4
| |
LL | fn eq<T>(x: T, y: T) {} LL | fn eq<T>(x: T, y: T) {}
| ^^ ---- | ^^ - ---- ----
| | | |
| | | this parameter needs to match the fn item type of `x`
| | `y` needs to match the type of this parameter
| `x` and `y` all reference this parameter T
= help: consider casting both fn items to fn pointers using `as fn()` = help: consider casting both fn items to fn pointers using `as fn()`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/fn-item-type.rs:45:19 --> $DIR/fn-item-type.rs:45:19
| |
LL | eq(foo::<u8>, bar::<u8> as fn(isize) -> isize); LL | eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
| -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer | -- --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
| | | | |
| | expected argument `y` to be a fn item because that argument needs to match the type of this parameter
| arguments to this function are incorrect | arguments to this function are incorrect
| |
= note: expected fn item `fn(_) -> _ {foo::<u8>}` = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@ -85,7 +106,11 @@ note: function defined here
--> $DIR/fn-item-type.rs:11:4 --> $DIR/fn-item-type.rs:11:4
| |
LL | fn eq<T>(x: T, y: T) {} LL | fn eq<T>(x: T, y: T) {}
| ^^ ---- | ^^ - ---- ----
| | | |
| | | this parameter needs to match the fn item type of `x`
| | `y` needs to match the type of this parameter
| `x` and `y` all reference this parameter T
error: aborting due to 5 previous errors error: aborting due to 5 previous errors

View File

@ -0,0 +1,12 @@
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
}

View File

@ -0,0 +1,75 @@
error[E0308]: mismatched types
--> $DIR/generic-mismatch-reporting-issue-116615.rs:6:12
|
LL | 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
--> $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 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 arguments `c`, `d` and `e` to be an `&str` because those arguments need to match the type of this parameter
| expected arguments `c`, `d` and `e` to be an `&str` because the arguments `b`, `c`, `d` and `e` need 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` needs to match the type of this parameter
| | `c`, `d` and `e` needs to match the 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 argument `g` to be an integer because that argument needs to match the type of this parameter
| | | | | expected `&str`, found `bool`
| | | | expected `&str`, found `bool`
| | | expected arguments `d` and `e` to be an `&str` because those arguments need to match the type of this parameter
| | expected arguments `d` and `e` to be an `&str` because the arguments `c`, `d` and `e` need to match the type of this parameter
| expected arguments `d` and `e` to be an `&str` because the arguments `b`, `c`, `d` and `e` need 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 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` needs to match the type of this parameter
| | | | `d` and `e` needs to match the type of this parameter
| | | `d` and `e` needs to match the type of this parameter
| | `a`, `b`, `c`, `d` and `e` all reference this parameter T
| `f` and `g` all reference this parameter S
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -21,6 +21,7 @@ LL | 0.....{loop{}1};
| | | | | |
| | expected integer, found `RangeTo<{integer}>` | | expected integer, found `RangeTo<{integer}>`
| arguments to this function are incorrect | arguments to this function are incorrect
| expected all arguments to be integer because they need to match the type of this parameter
| |
= note: expected type `{integer}` = note: expected type `{integer}`
found struct `RangeTo<{integer}>` found struct `RangeTo<{integer}>`

View File

@ -43,7 +43,7 @@ note: function defined here
--> $DIR/issue-93282.rs:7:4 --> $DIR/issue-93282.rs:7:4
| |
LL | fn bar(a: usize, b: usize) -> usize { LL | fn bar(a: usize, b: usize) -> usize {
| ^^^ -------- | ^^^ -------- --------
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View File

@ -77,7 +77,7 @@ note: function defined here
--> $DIR/issue-34264.rs:3:4 --> $DIR/issue-34264.rs:3:4
| |
LL | fn bar(x, y: usize) {} LL | fn bar(x, y: usize) {}
| ^^^ -------- | ^^^ - --------
error[E0061]: this function takes 2 arguments but 3 arguments were supplied error[E0061]: this function takes 2 arguments but 3 arguments were supplied
--> $DIR/issue-34264.rs:10:5 --> $DIR/issue-34264.rs:10:5

View File

@ -8,7 +8,7 @@ note: function defined here
--> $DIR/add-tuple-within-arguments.rs:1:4 --> $DIR/add-tuple-within-arguments.rs:1:4
| |
LL | fn foo(s: &str, a: (i32, i32), s2: &str) {} LL | fn foo(s: &str, a: (i32, i32), s2: &str) {}
| ^^^ ------------- | ^^^ ------- ------------- --------
help: wrap these arguments in parentheses to construct a tuple help: wrap these arguments in parentheses to construct a tuple
| |
LL | foo("hi", (1, 2), "hi"); LL | foo("hi", (1, 2), "hi");
@ -28,7 +28,7 @@ note: function defined here
--> $DIR/add-tuple-within-arguments.rs:3:4 --> $DIR/add-tuple-within-arguments.rs:3:4
| |
LL | fn bar(s: &str, a: (&str,), s2: &str) {} LL | fn bar(s: &str, a: (&str,), s2: &str) {}
| ^^^ ---------- | ^^^ ------- ---------- --------
help: use a trailing comma to create a tuple with one element help: use a trailing comma to create a tuple with one element
| |
LL | bar("hi", ("hi",), "hi"); LL | bar("hi", ("hi",), "hi");

View File

@ -74,7 +74,7 @@ note: function defined here
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4 --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
| |
LL | fn function<T>(x: T, y: bool) -> T { LL | fn function<T>(x: T, y: bool) -> T {
| ^^^^^^^^ ---- | ^^^^^^^^ ---- -------
help: change the type of the numeric literal from `u32` to `u16` help: change the type of the numeric literal from `u32` to `u16`
| |
LL | let x: u16 = function(0u16, true); LL | let x: u16 = function(0u16, true);