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 @@
fallback_fluent_bundle, fluent_bundle, DelayDm, DiagMessage, FluentBundle, LanguageIdentifier,
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::ErrorGuaranteed;
pub use snippet::Style;

View File

@ -17,7 +17,8 @@
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,
DiagnosticBuilder, ErrorGuaranteed, MultiSpan, StashKey,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
@ -423,11 +424,7 @@ fn variadic_error<'tcx>(
"expected formal_input_tys to be the same size as expected_input_tys"
);
let formal_and_expected_inputs = IndexVec::from_iter(
formal_input_tys
.iter()
.copied()
.zip_eq(expected_input_tys.iter().copied())
.map(|vars| self.resolve_vars_if_possible(vars)),
formal_input_tys.iter().copied().zip_eq(expected_input_tys.iter().copied()),
);
self.set_tainted_by_errors(self.report_arg_errors(
@ -642,6 +639,8 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
}
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
// coercible. This prevents our error message heuristic from trying to pass errors into
// every argument.
@ -714,7 +713,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
// 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 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.
&& !tys.is_empty()
&& provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
@ -733,7 +732,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
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;
break;
}
@ -752,10 +751,14 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
if tys.len() == 1 {
// A tuple wrap suggestion actually occurs within,
// 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(
mk_trace(
*lo,
formal_and_expected_inputs[mismatch_idx.into()],
(formal_ty, expected_ty),
provided_arg_tys[mismatch_idx.into()].0,
),
terr,
@ -795,6 +798,8 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
call_expr,
None,
Some(mismatch_idx),
&matched_inputs,
&formal_and_expected_inputs,
is_method,
);
suggest_confusable(&mut err);
@ -837,8 +842,10 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
return true;
};
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
let trace =
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
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 trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
let mut err = self.err_ctxt().report_and_explain_type_error(trace, *e);
suggest_confusable(&mut err);
@ -866,6 +873,8 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
] = &errors[..]
{
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 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);
@ -881,6 +890,14 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
);
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
&& provided_idx.as_usize() == expected_idx.as_usize()
{
@ -909,6 +926,8 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
call_expr,
Some(expected_ty),
Some(expected_idx.as_usize()),
&matched_inputs,
&formal_and_expected_inputs,
is_method,
);
suggest_confusable(&mut err);
@ -984,6 +1003,8 @@ enum SuggestionText {
match error {
Error::Invalid(provided_idx, expected_idx, compatibility) => {
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];
if let Compatibility::Incompatible(error) = compatibility {
let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
@ -1088,6 +1109,7 @@ enum SuggestionText {
match &missing_idxs[..] {
&[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)) =
provided_arg_tys.get(expected_idx.to_provided_idx())
{
@ -1110,6 +1132,10 @@ enum SuggestionText {
&[first_idx, second_idx] => {
let (_, first_expected_ty) = formal_and_expected_inputs[first_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))) = (
provided_arg_tys.get(first_idx.to_provided_idx()),
provided_arg_tys.get(second_idx.to_provided_idx()),
@ -1136,8 +1162,14 @@ enum SuggestionText {
}
&[first_idx, second_idx, third_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 =
self.resolve_vars_if_possible(second_expected_ty);
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))) = (
provided_arg_tys.get(first_idx.to_provided_idx()),
provided_arg_tys.get(third_idx.to_provided_idx()),
@ -1197,6 +1229,7 @@ enum SuggestionText {
) => {
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 = self.resolve_vars_if_possible(first_expected_ty);
let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) {
format!(", found `{first_provided_ty}`")
} else {
@ -1209,6 +1242,7 @@ enum SuggestionText {
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_provided_ty = self.resolve_vars_if_possible(second_provided_ty);
let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) {
format!(", found `{second_provided_ty}`")
} else {
@ -1227,6 +1261,7 @@ enum SuggestionText {
Error::Permutation(args) => {
for (dst_arg, dest_input) in args {
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_name = if !has_error_or_infer([provided_ty]) {
format!(", found `{provided_ty}`")
@ -1247,6 +1282,14 @@ enum SuggestionText {
}
}
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.
// 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
@ -1282,6 +1325,7 @@ enum SuggestionText {
// To suggest a multipart suggestion when encountering `foo(1, "")` where the def
// was `fn foo(())`.
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)));
}
}
@ -1294,7 +1338,17 @@ enum SuggestionText {
}
// 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 {
@ -1348,6 +1402,7 @@ enum SuggestionText {
} else {
// Propose a placeholder of the correct type
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)
};
suggestion += &suggestion_text;
@ -2054,6 +2109,8 @@ fn label_fn_like(
expected_ty: Option<Ty<'tcx>>,
// A specific argument should be labeled, instead of all of them
expected_idx: Option<usize>,
matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
is_method: bool,
) {
let Some(mut def_id) = callable_def_id else {
@ -2145,21 +2202,200 @@ fn label_fn_like(
{
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
.hir()
.get_if_local(def_id)
.and_then(|node| node.body_id())
.into_iter()
.flat_map(|id| self.tcx.hir().body(id).params)
.skip(if is_method { 1 } else { 0 });
.skip(if is_method { 1 } else { 0 })
.collect();
for (_, param) in params
.into_iter()
.enumerate()
.filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx))
{
spans.push_span_label(param.span, "");
if params.len() == param_generics.len() {
let mut generics_map: Vec<(usize, &hir::GenericParam<'_>)> = Vec::new();
// This is a map from the index of the generic to the index of the parameter and the
// 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, "");
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)));
@ -2225,6 +2461,118 @@ fn label_fn_like(
);
}
}
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> {

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

View File

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

View File

@ -11,9 +11,31 @@ note: method defined here
|
LL | fn foo(
| ^^^
...
LL | &self,
LL | a: i32,
| ------
LL | b: i32,
| ------
LL | c: i32,
| ------
LL | d: i32,
| ------
LL | e: 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
|
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
| | |
| | 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
|
= 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
|
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
--> $DIR/coroutine-desc.rs:12:16
|
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
|
= help: consider `await`ing on both `Future`s
@ -29,15 +35,20 @@ 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 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 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
|
= 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
|
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

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 argument `_b` to be an `&mut {integer}` because that argument needs to match the type of this parameter
| arguments to this function are incorrect
|
= note: expected mutable reference `&mut {integer}`
@ -12,7 +13,11 @@ 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 type of this parameter
| `_a` and `_b` all reference this parameter T
error: aborting due to 1 previous error

View File

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

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 argument `y` to be a fn item because that argument needs to match the type of this parameter
| arguments to this function are incorrect
|
= note: expected fn item `fn(_) -> _ {foo::<u8>}`
@ -13,15 +14,20 @@ 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 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 argument `y` to be a fn item because that argument needs to match the type of this parameter
| arguments to this function are incorrect
|
= note: expected fn item `fn(_) -> _ {foo::<u8>}`
@ -31,15 +37,20 @@ 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 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 argument `y` to be a fn item because that argument needs to match the type of this parameter
| arguments to this function are incorrect
|
= note: expected fn item `fn(_) -> _ {bar::<String>}`
@ -49,15 +60,20 @@ 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 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 argument `y` to be a fn item because that argument needs to match the type of this parameter
| arguments to this function are incorrect
|
= note: expected fn item `fn() {<u8 as Foo>::foo}`
@ -67,15 +83,20 @@ 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 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 argument `y` to be a fn item because that argument needs to match the type of this parameter
| arguments to this function are incorrect
|
= note: expected fn item `fn(_) -> _ {foo::<u8>}`
@ -85,7 +106,11 @@ 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 type of this parameter
| `x` and `y` all reference this parameter T
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}>`
| 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}`
found struct `RangeTo<{integer}>`

View File

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

View File

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

View File

@ -8,7 +8,7 @@ note: function defined here
--> $DIR/add-tuple-within-arguments.rs:1:4
|
LL | fn foo(s: &str, a: (i32, i32), s2: &str) {}
| ^^^ -------------
| ^^^ ------- ------------- --------
help: wrap these arguments in parentheses to construct a tuple
|
LL | foo("hi", (1, 2), "hi");
@ -28,7 +28,7 @@ note: function defined here
--> $DIR/add-tuple-within-arguments.rs:3:4
|
LL | fn bar(s: &str, a: (&str,), s2: &str) {}
| ^^^ ----------
| ^^^ ------- ---------- --------
help: use a trailing comma to create a tuple with one element
|
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
|
LL | fn function<T>(x: T, y: bool) -> T {
| ^^^^^^^^ ----
| ^^^^^^^^ ---- -------
help: change the type of the numeric literal from `u32` to `u16`
|
LL | let x: u16 = function(0u16, true);