diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 73cda64f1cc6a..1fb16ae6cbe89 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -53,7 +53,7 @@ pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage, }; -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; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 2d9ec9f6bab8c..e85d846606bad 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -13,7 +13,8 @@ use itertools::Itertools; use rustc_ast as ast; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ - codes::*, pluralize, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, StashKey, + a_or_an, codes::*, display_list_with_comma_and, pluralize, Applicability, DiagnosticBuilder, + ErrorGuaranteed, MultiSpan, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -419,11 +420,7 @@ impl<'a, 'tcx> FnCtxt<'a, '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( @@ -509,7 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .borrow() .expr_ty_adjusted_opt(*expr) .unwrap_or_else(|| Ty::new_misc_error(tcx)); - (self.resolve_vars_if_possible(ty), normalize_span(expr.span)) + (ty, normalize_span(expr.span)) }) .collect(); let callee_expr = match &call_expr.peel_blocks().kind { @@ -539,6 +536,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } 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. @@ -547,6 +546,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let (arg_ty, arg_span) = provided_arg_tys[provided_idx]; + let arg_ty = self.resolve_vars_if_possible(arg_ty); let expectation = Expectation::rvalue_hint(self, expected_input_ty); let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); @@ -611,7 +611,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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() @@ -619,7 +619,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Wrap up the N provided arguments starting at this position in a tuple. let provided_as_tuple = Ty::new_tup_from_iter( tcx, - provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()), + provided_arg_tys + .iter() + .map(|(ty, _)| self.resolve_vars_if_possible(*ty)) + .skip(mismatch_idx) + .take(tys.len()), ); let mut satisfied = true; @@ -630,7 +634,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), ), ) { - if !self.can_coerce(provided_ty, *expected_ty) { + if !self.can_coerce( + self.resolve_vars_if_possible(provided_ty), + self.resolve_vars_if_possible(*expected_ty), + ) { satisfied = false; break; } @@ -649,11 +656,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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()], - provided_arg_tys[mismatch_idx.into()].0, + (formal_ty, expected_ty), + self.resolve_vars_if_possible( + provided_arg_tys[mismatch_idx.into()], + ) + .0, ), terr, ); @@ -692,6 +706,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr, None, Some(mismatch_idx), + &matched_inputs, + &formal_and_expected_inputs, is_method, ); return err.emit(); @@ -730,8 +746,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 provided_ty = self.resolve_vars_if_possible(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) { reported = Some(self.err_ctxt().report_and_explain_type_error(trace, *e).emit()); return false; @@ -757,7 +776,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ] = &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 provided_ty = self.resolve_vars_if_possible(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); self.emit_coerce_suggestions( @@ -772,6 +794,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect")); + self.emit_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() { @@ -800,6 +830,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr, Some(expected_ty), Some(expected_idx.as_usize()), + &matched_inputs, + &formal_and_expected_inputs, is_method, ); return err.emit(); @@ -873,7 +905,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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]; + let provided_ty = self.resolve_vars_if_possible(provided_ty); if let Compatibility::Incompatible(error) = compatibility { let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); if let Some(e) = error { @@ -902,6 +937,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Error::Extra(arg_idx) => { let (provided_ty, provided_span) = provided_arg_tys[arg_idx]; + let provided_ty = self.resolve_vars_if_possible(provided_ty); let provided_ty_name = if !has_error_or_infer([provided_ty]) { // FIXME: not suggestable, use something else format!(" of type `{provided_ty}`") @@ -977,6 +1013,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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()) { @@ -984,11 +1021,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { args_span }; - let rendered = if !has_error_or_infer([input_ty]) { - format!(" of type `{input_ty}`") - } else { - "".to_string() - }; + let rendered = + if !has_error_or_infer([self.resolve_vars_if_possible(input_ty)]) { + format!(" of type `{input_ty}`") + } else { + "".to_string() + }; labels.push((span, format!("an argument{rendered} is missing"))); suggestion_text = match suggestion_text { SuggestionText::None => SuggestionText::Provide(false), @@ -999,6 +1037,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[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()), @@ -1025,8 +1067,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } &[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()), @@ -1085,7 +1133,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { second_expected_idx, ) => { let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; + let first_provided_ty = self.resolve_vars_if_possible(first_provided_ty); 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 { @@ -1097,7 +1147,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; + let second_provided_ty = self.resolve_vars_if_possible(second_provided_ty); 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 { @@ -1116,7 +1168,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 = self.resolve_vars_if_possible(provided_ty); let provided_ty_name = if !has_error_or_infer([provided_ty]) { format!(", found `{provided_ty}`") } else { @@ -1136,6 +1190,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + self.emit_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 @@ -1171,6 +1233,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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))); } } @@ -1183,7 +1246,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Call out where the function is defined - self.label_fn_like(&mut err, fn_def_id, callee_ty, call_expr, None, None, is_method); + self.label_fn_like( + &mut err, + fn_def_id, + callee_ty, + call_expr, + None, + None, + &matched_inputs, + &formal_and_expected_inputs, + is_method, + ); // And add a suggestion block for all of the parameters let suggestion_text = match suggestion_text { @@ -1237,6 +1310,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } 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; @@ -1943,6 +2017,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Option>, // A specific argument should be labeled, instead of all of them expected_idx: Option, + matched_inputs: &IndexVec>, + formal_and_expected_inputs: &IndexVec, Ty<'tcx>)>, is_method: bool, ) { let Some(mut def_id) = callable_def_id else { @@ -2034,21 +2110,201 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let mut spans: MultiSpan = def_span.into(); - let params = self + let param_generics: Vec>> = 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(); + + if params.len() == param_generics.len() { + // TODO: IndexVec or something like that from data structures better? + 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; + } - 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, ""); + 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 = 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 = 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 = 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))); @@ -2112,6 +2368,118 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } + + fn emit_generic_mismatches( + &self, + err: &mut DiagnosticBuilder<'_>, + callable_def_id: Option, + matched_inputs: &IndexVec>, + provided_arg_tys: &IndexVec, Span)>, + formal_and_expected_inputs: &IndexVec, 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 = 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.check_ty_vars_equal(*a, *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 = vec![]; + let mut incompatible_pats_matched: Vec = 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> { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 243558b11a863..c78204dee75bc 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1370,6 +1370,11 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().effect_unification_table().find(var).vid } + /// Check variables are equal + pub fn check_ty_vars_equal(&self, a: ty::TyVid, b: ty::TyVid) -> bool { + self.inner.borrow_mut().type_variables().check_equal(a, b) + } + /// Resolves an int var to a rigid int type, if it was constrained to one, /// or else the root int var in the unification table. pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 8b81eac873909..820f2ecb6233d 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -284,6 +284,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { self.sub_root_var(a) == self.sub_root_var(b) } + /// Returns `true` if `a` and `b` have same "root" (i.e., `a == b`). + pub fn check_equal(&mut self, a: ty::TyVid, b: ty::TyVid) -> bool { + self.root_var(a) == self.root_var(b) + } + /// Retrieves the type to which `vid` has been instantiated, if /// any. pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index d4e5c78c492c7..da7e8e8bb9ad7 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -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(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 diff --git a/tests/ui/argument-suggestions/extra_arguments.stderr b/tests/ui/argument-suggestions/extra_arguments.stderr index 5ad8e35920a10..4cbe9124deec1 100644 --- a/tests/ui/argument-suggestions/extra_arguments.stderr +++ b/tests/ui/argument-suggestions/extra_arguments.stderr @@ -45,7 +45,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_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(_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(_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(_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(_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(_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(_a: T) {} - | ^^^^^^^ ----- + | ^^^^^^^ error: aborting due to 22 previous errors diff --git a/tests/ui/argument-suggestions/invalid_arguments.stderr b/tests/ui/argument-suggestions/invalid_arguments.stderr index d26f33d098be0..61a46b067f5bc 100644 --- a/tests/ui/argument-suggestions/invalid_arguments.stderr +++ b/tests/ui/argument-suggestions/invalid_arguments.stderr @@ -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 diff --git a/tests/ui/argument-suggestions/too-long.stderr b/tests/ui/argument-suggestions/too-long.stderr index 04ee9275cb363..9400f2a02a827 100644 --- a/tests/ui/argument-suggestions/too-long.stderr +++ b/tests/ui/argument-suggestions/too-long.stderr @@ -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); diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr index e4cb0915a1090..5ad54bc5b8e3f 100644 --- a/tests/ui/async-await/coroutine-desc.stderr +++ b/tests/ui/async-await/coroutine-desc.stderr @@ -5,6 +5,7 @@ LL | fun(async {}, async {}); | --- -------- ^^^^^^^^ expected `async` block, found a different `async` block | | | | | the expected `async` block + | | expected 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>(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>(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>(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 diff --git a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr index 498ef33d52ecc..b67f91ff8e28d 100644 --- a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr +++ b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr @@ -2,8 +2,9 @@ error[E0308]: mismatched types --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18 | LL | test(&mut 7, &7); - | ---- ^^ types differ in mutability - | | + | ---- ------ ^^ types differ in mutability + | | | + | | expected 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(_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 diff --git a/tests/ui/coercion/coerce-to-bang.stderr b/tests/ui/coercion/coerce-to-bang.stderr index 3c737358adc77..4c21eef5c2917 100644 --- a/tests/ui/coercion/coerce-to-bang.stderr +++ b/tests/ui/coercion/coerce-to-bang.stderr @@ -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 diff --git a/tests/ui/fn/fn-item-type.stderr b/tests/ui/fn/fn-item-type.stderr index da90b8b81c855..24c7a3cb4828a 100644 --- a/tests/ui/fn/fn-item-type.stderr +++ b/tests/ui/fn/fn-item-type.stderr @@ -2,8 +2,9 @@ error[E0308]: mismatched types --> $DIR/fn-item-type.rs:22:19 | LL | eq(foo::, bar::); - | -- ^^^^^^^^^ 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::}` @@ -13,15 +14,20 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(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::, foo::); - | -- ^^^^^^^^^ 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::}` @@ -31,15 +37,20 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(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::, bar::>); - | -- ^^^^^^^^^^^^^^ expected `String`, found `Vec` - | | + | -- ------------- ^^^^^^^^^^^^^^ expected `String`, found `Vec` + | | | + | | 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::}` @@ -49,15 +60,20 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(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(::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() {::foo}` @@ -67,15 +83,20 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(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::, bar:: 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::}` @@ -85,7 +106,11 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(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 diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs new file mode 100644 index 0000000000000..9a38b948e8ea5 --- /dev/null +++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs @@ -0,0 +1,12 @@ +fn foo(a: T, b: T) {} +fn foo_multi_same(a: T, b: T, c: T, d: T, e: T, f: i32) {} +fn foo_multi_generics(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 +} diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr new file mode 100644 index 0000000000000..a4f55ce06ac76 --- /dev/null +++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr @@ -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(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(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(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`. diff --git a/tests/ui/never_type/issue-96335.stderr b/tests/ui/never_type/issue-96335.stderr index c3d80a425e057..13cdbe842c9dc 100644 --- a/tests/ui/never_type/issue-96335.stderr +++ b/tests/ui/never_type/issue-96335.stderr @@ -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}>` diff --git a/tests/ui/parser/issues/issue-93282.stderr b/tests/ui/parser/issues/issue-93282.stderr index c6140bb821e48..fc15865e1a729 100644 --- a/tests/ui/parser/issues/issue-93282.stderr +++ b/tests/ui/parser/issues/issue-93282.stderr @@ -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 diff --git a/tests/ui/span/issue-34264.stderr b/tests/ui/span/issue-34264.stderr index f0dea66f6128d..1b9ad3a3f1675 100644 --- a/tests/ui/span/issue-34264.stderr +++ b/tests/ui/span/issue-34264.stderr @@ -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 diff --git a/tests/ui/tuple/add-tuple-within-arguments.stderr b/tests/ui/tuple/add-tuple-within-arguments.stderr index 6849128eaddde..8414a51bfd5e8 100644 --- a/tests/ui/tuple/add-tuple-within-arguments.stderr +++ b/tests/ui/tuple/add-tuple-within-arguments.stderr @@ -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"); diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr index fbe6bfeebb149..63a98a55127a8 100644 --- a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr +++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr @@ -74,7 +74,7 @@ note: function defined here --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4 | LL | fn function(x: T, y: bool) -> T { - | ^^^^^^^^ ---- + | ^^^^^^^^ ---- ------- help: change the type of the numeric literal from `u32` to `u16` | LL | let x: u16 = function(0u16, true);