Skip to content

Commit 27e2804

Browse files
committed
WIP
1 parent 446fc6a commit 27e2804

File tree

5 files changed

+134
-138
lines changed

5 files changed

+134
-138
lines changed

compiler/rustc_errors/src/lib.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub use rustc_error_messages::{
5050
fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle,
5151
LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage,
5252
};
53-
pub use rustc_lint_defs::{a_or_an, display_list_with_comma_and, pluralize, Applicability};
53+
pub use rustc_lint_defs::{pluralize, Applicability};
5454
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
5555
pub use rustc_span::ErrorGuaranteed;
5656
pub use snippet::Style;
@@ -1867,6 +1867,39 @@ pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
18671867
}
18681868
}
18691869

1870+
/// Grammatical tool for displaying messages to end users in a nice form.
1871+
///
1872+
/// Returns "an" if the given string starts with a vowel, and "a" otherwise.
1873+
pub fn a_or_an(s: &str) -> &'static str {
1874+
let mut chars = s.chars();
1875+
let Some(mut first_alpha_char) = chars.next() else {
1876+
return "a";
1877+
};
1878+
if first_alpha_char == '`' {
1879+
let Some(next) = chars.next() else {
1880+
return "a";
1881+
};
1882+
first_alpha_char = next;
1883+
}
1884+
if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
1885+
"an"
1886+
} else {
1887+
"a"
1888+
}
1889+
}
1890+
1891+
/// Grammatical tool for displaying messages to end users in a nice form.
1892+
///
1893+
/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
1894+
pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
1895+
match v.len() {
1896+
0 => "".to_string(),
1897+
1 => v[0].to_string(),
1898+
2 => format!("{} and {}", v[0], v[1]),
1899+
_ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])),
1900+
}
1901+
}
1902+
18701903
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
18711904
pub enum TerminalUrl {
18721905
No,

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 83 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_ast as ast;
1818
use rustc_data_structures::fx::FxIndexSet;
1919
use rustc_errors::{
2020
a_or_an, codes::*, display_list_with_comma_and, pluralize, Applicability, Diag,
21-
DiagnosticBuilder, ErrorGuaranteed, MultiSpan, StashKey,
21+
ErrorGuaranteed, MultiSpan, StashKey,
2222
};
2323
use rustc_hir as hir;
2424
use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -2202,81 +2202,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22022202
{
22032203
let mut spans: MultiSpan = def_span.into();
22042204

2205-
let param_generics: Vec<Option<&hir::GenericParam<'_>>> = self
2206-
.tcx
2207-
.hir()
2208-
.get_if_local(def_id)
2209-
.and_then(|node| node.fn_decl())
2210-
.into_iter()
2211-
.flat_map(|decl| decl.inputs)
2212-
.skip(if is_method { 1 } else { 0 })
2213-
.map(|param| {
2214-
if let hir::TyKind::Path(QPath::Resolved(
2215-
_,
2216-
hir::Path { res: Res::Def(_, res_def_id), .. },
2217-
)) = param.kind
2218-
{
2219-
self.tcx
2220-
.hir()
2221-
.get_if_local(def_id)
2222-
.and_then(|node| node.generics())
2223-
.into_iter()
2224-
.flat_map(|generics| generics.params)
2225-
.find(|gen| &gen.def_id.to_def_id() == res_def_id)
2226-
} else {
2227-
None
2228-
}
2229-
})
2230-
.collect();
2205+
let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
22312206

2232-
let params: Vec<&hir::Param<'_>> = self
2233-
.tcx
2234-
.hir()
2235-
.get_if_local(def_id)
2236-
.and_then(|node| node.body_id())
2237-
.into_iter()
2238-
.flat_map(|id| self.tcx.hir().body(id).params)
2239-
.skip(if is_method { 1 } else { 0 })
2240-
.collect();
2241-
2242-
let check_for_matched_generics_fn = || {
2243-
if params.len() == param_generics.len()
2244-
&& matched_inputs.iter().any(|x| x.is_some())
2245-
&& param_generics.iter().any(|x| x.is_some())
2246-
{
2247-
for (idx, generic) in param_generics.iter().enumerate() {
2248-
if matched_inputs[idx.into()].is_none() {
2249-
continue;
2250-
}
2207+
let mut check_for_matched_generics = false;
2208+
if matched_inputs.iter().any(|x| x.is_some())
2209+
&& params_with_generics.iter().any(|x| x.0.is_some())
2210+
{
2211+
for (idx, (generic, _)) in params_with_generics.iter().enumerate() {
2212+
// Param has to have a generic and be matched to be relevant
2213+
if matched_inputs[idx.into()].is_none() {
2214+
continue;
2215+
}
22512216

2252-
let Some(generic) = generic else {
2253-
continue;
2254-
};
2217+
let Some(generic) = generic else {
2218+
continue;
2219+
};
22552220

2256-
for unmatching_idx in idx + 1..params.len() {
2257-
if matched_inputs[unmatching_idx.into()].is_none()
2258-
&& let Some(unmatched_idx_param_generic) =
2259-
param_generics[unmatching_idx]
2260-
&& unmatched_idx_param_generic.name.ident() == generic.name.ident()
2261-
{
2262-
return true;
2263-
}
2221+
for unmatching_idx in idx + 1..params_with_generics.len() {
2222+
if matched_inputs[unmatching_idx.into()].is_none()
2223+
&& let Some(unmatched_idx_param_generic) =
2224+
params_with_generics[unmatching_idx].0
2225+
&& unmatched_idx_param_generic.name.ident() == generic.name.ident()
2226+
{
2227+
// We found a parameter that didn't match that needed to
2228+
check_for_matched_generics = true;
22642229
}
22652230
}
22662231
}
2267-
false
2268-
};
2232+
}
22692233

2270-
if check_for_matched_generics_fn() {
2234+
if check_for_matched_generics {
22712235
let mut generics_map: Vec<(usize, &hir::GenericParam<'_>)> = Vec::new();
22722236
// This is a map from the index of the generic to the index of the parameter and the
22732237
// parameter
22742238
let mut matched_params_map: Vec<(usize, usize, &hir::Param<'_>)> = Vec::new();
22752239
let mut unmatched_params_map: Vec<(usize, &hir::Param<'_>)> = Vec::new();
22762240

2277-
for (idx, (param, generic)) in
2278-
params.iter().zip_eq(param_generics.iter()).enumerate()
2279-
{
2241+
for (idx, (generic, param)) in params_with_generics.iter().enumerate() {
22802242
if matched_inputs[idx.into()].is_none() {
22812243
spans.push_span_label(param.span, "");
22822244
continue;
@@ -2289,13 +2251,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22892251

22902252
let mut found_unmatched_generic_params = vec![];
22912253

2292-
for unmatching_idx in idx + 1..params.len() {
2254+
for unmatching_idx in idx + 1..params_with_generics.len() {
22932255
if matched_inputs[unmatching_idx.into()].is_none()
22942256
&& let Some(unmatched_idx_param_generic) =
2295-
param_generics[unmatching_idx]
2257+
params_with_generics[unmatching_idx].0
22962258
&& unmatched_idx_param_generic.name.ident() == generic.name.ident()
22972259
{
2298-
found_unmatched_generic_params.push(params[unmatching_idx]);
2260+
found_unmatched_generic_params
2261+
.push(params_with_generics[unmatching_idx].1);
22992262
}
23002263
}
23012264

@@ -2398,7 +2361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23982361
}
23992362
}
24002363

2401-
for matched_param in &matched_params {
2364+
for (idx, matched_param) in matched_params.iter().enumerate() {
24022365
let idents: Vec<String> = unmatched_params
24032366
.iter()
24042367
.map(|x| {
@@ -2410,17 +2373,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24102373
})
24112374
.collect();
24122375

2376+
let matched_ty = self
2377+
.resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].0)
2378+
.sort_string(self.tcx);
2379+
24132380
spans.push_span_label(
24142381
matched_param.1.span,
24152382
format!(
2416-
"{} needs to match the type of this parameter",
2417-
display_list_with_comma_and(&idents)
2383+
"{} {} to match the {} type of this parameter",
2384+
display_list_with_comma_and(&idents),
2385+
format!(
2386+
"need{}",
2387+
pluralize!(if idents.len() == 1 { 0 } else { 1 })
2388+
),
2389+
matched_ty,
24182390
),
24192391
);
24202392
}
24212393
}
24222394
} else {
2423-
for (_, param) in params.iter().enumerate().filter(|(idx, _)| {
2395+
for (_, (_, param)) in params_with_generics.iter().enumerate().filter(|(idx, _)| {
24242396
expected_idx.map_or(true, |expected_idx| expected_idx == *idx)
24252397
}) {
24262398
spans.push_span_label(param.span, "");
@@ -2491,7 +2463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24912463

24922464
fn label_generic_mismatches(
24932465
&self,
2494-
err: &mut DiagnosticBuilder<'_>,
2466+
err: &mut Diag<'_>,
24952467
callable_def_id: Option<DefId>,
24962468
matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
24972469
provided_arg_tys: &IndexVec<ProvidedIdx, (Ty<'tcx>, Span)>,
@@ -2571,35 +2543,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25712543
"expected all arguments to be {} because they need to match the type of this parameter",
25722544
expected_display_type
25732545
)
2574-
} else if all_pats_matched.len() == incompatible_pats_matched.len() {
2575-
format!(
2576-
"expected {} {} to be {} {} because {} to match the type of this parameter",
2577-
format!("argument{}", pluralize!(incompatible_pats_matched.len())),
2578-
display_list_with_comma_and(&incompatible_pats_matched),
2579-
a_or_an(&expected_display_type),
2580-
expected_display_type,
2581-
if all_pats_matched.len() == 1 {
2582-
"that argument needs"
2583-
} else {
2584-
"those arguments need"
2585-
}
2586-
)
25872546
} else {
25882547
format!(
2589-
"expected {} {} to be {} {} because the {} {} {} to match the type of this parameter",
2590-
format!("argument{}", pluralize!(incompatible_pats_matched.len())),
2591-
display_list_with_comma_and(&incompatible_pats_matched),
2548+
"expected some other arguments to be {} {} to match the type of this parameter",
25922549
a_or_an(&expected_display_type),
25932550
expected_display_type,
2594-
format!("argument{}", pluralize!(all_pats_matched.len())),
2595-
display_list_with_comma_and(&all_pats_matched),
2596-
format!("need{}", pluralize!(if all_pats_matched.len() == 1 { 0 } else { 1 })),
25972551
)
25982552
};
25992553

26002554
err.span_label(matched_arg_span, label);
26012555
}
26022556
}
2557+
2558+
fn get_hir_params_with_generics(
2559+
&self,
2560+
def_id: DefId,
2561+
is_method: bool,
2562+
) -> Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)> {
2563+
let fn_node = self.tcx.hir().get_if_local(def_id);
2564+
2565+
let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node
2566+
.and_then(|node| node.fn_decl())
2567+
.into_iter()
2568+
.flat_map(|decl| decl.inputs)
2569+
.skip(if is_method { 1 } else { 0 })
2570+
.map(|param| {
2571+
if let hir::TyKind::Path(QPath::Resolved(
2572+
_,
2573+
hir::Path { res: Res::Def(_, res_def_id), .. },
2574+
)) = param.kind
2575+
{
2576+
fn_node
2577+
.and_then(|node| node.generics())
2578+
.into_iter()
2579+
.flat_map(|generics| generics.params)
2580+
.find(|gen| &gen.def_id.to_def_id() == res_def_id)
2581+
} else {
2582+
None
2583+
}
2584+
})
2585+
.collect();
2586+
2587+
let params: Vec<&hir::Param<'_>> = fn_node
2588+
.and_then(|node| node.body_id())
2589+
.into_iter()
2590+
.flat_map(|id| self.tcx.hir().body(id).params)
2591+
.skip(if is_method { 1 } else { 0 })
2592+
.collect();
2593+
2594+
generic_params.into_iter().zip(params).collect()
2595+
}
26032596
}
26042597

26052598
struct FindClosureArg<'tcx> {

compiler/rustc_lint_defs/src/lib.rs

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -39,39 +39,6 @@ macro_rules! pluralize {
3939
};
4040
}
4141

42-
/// Grammatical tool for displaying messages to end users in a nice form.
43-
///
44-
/// Returns "an" if the given string starts with a vowel, and "a" otherwise.
45-
pub fn a_or_an(s: &str) -> &'static str {
46-
let mut chars = s.chars();
47-
let Some(mut first_alpha_char) = chars.next() else {
48-
return "a";
49-
};
50-
if first_alpha_char == '`' {
51-
let Some(next) = chars.next() else {
52-
return "a";
53-
};
54-
first_alpha_char = next;
55-
}
56-
if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
57-
"an"
58-
} else {
59-
"a"
60-
}
61-
}
62-
63-
/// Grammatical tool for displaying messages to end users in a nice form.
64-
///
65-
/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
66-
pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
67-
match v.len() {
68-
0 => "".to_string(),
69-
1 => v[0].to_string(),
70-
2 => format!("{} and {}", v[0], v[1]),
71-
_ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])),
72-
}
73-
}
74-
7542
/// Indicates the confidence in the correctness of a suggestion.
7643
///
7744
/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion

tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
fn foo<T>(a: T, b: T) {}
22
fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
33
fn foo_multi_generics<S, T>(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {}
4+
fn foo_same_generics<T, T>(a: T, b: T, c: T, d: T) {}
45

56
fn main() {
67
foo(1, 2.);
@@ -9,4 +10,6 @@ fn main() {
910
//~^ ERROR arguments to this function are incorrect
1011
foo_multi_generics("a", "b", "c", true, false, 32, 2.);
1112
//~^ ERROR arguments to this function are incorrect
13+
foo_same_generics("a", 1, "c", 2);
14+
//~^ ERROR arguments to this function are incorrect
1215
}

0 commit comments

Comments
 (0)