Skip to content

Commit 7983eab

Browse files
committed
WIP
1 parent 27e2804 commit 7983eab

File tree

6 files changed

+211
-183
lines changed

6 files changed

+211
-183
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 134 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -2203,12 +2203,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22032203
let mut spans: MultiSpan = def_span.into();
22042204

22052205
let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
2206+
let mut generics_with_unmatched_params = Vec::new();
22062207

22072208
let mut check_for_matched_generics = false;
22082209
if matched_inputs.iter().any(|x| x.is_some())
22092210
&& params_with_generics.iter().any(|x| x.0.is_some())
22102211
{
22112212
for (idx, (generic, _)) in params_with_generics.iter().enumerate() {
2213+
if check_for_matched_generics {
2214+
break;
2215+
}
2216+
22122217
// Param has to have a generic and be matched to be relevant
22132218
if matched_inputs[idx.into()].is_none() {
22142219
continue;
@@ -2226,146 +2231,106 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22262231
{
22272232
// We found a parameter that didn't match that needed to
22282233
check_for_matched_generics = true;
2234+
break;
22292235
}
22302236
}
22312237
}
22322238
}
22332239

2234-
if check_for_matched_generics {
2235-
let mut generics_map: Vec<(usize, &hir::GenericParam<'_>)> = Vec::new();
2236-
// This is a map from the index of the generic to the index of the parameter and the
2237-
// parameter
2238-
let mut matched_params_map: Vec<(usize, usize, &hir::Param<'_>)> = Vec::new();
2239-
let mut unmatched_params_map: Vec<(usize, &hir::Param<'_>)> = Vec::new();
2240-
2241-
for (idx, (generic, param)) in params_with_generics.iter().enumerate() {
2242-
if matched_inputs[idx.into()].is_none() {
2243-
spans.push_span_label(param.span, "");
2244-
continue;
2245-
}
2246-
2247-
let Some(generic) = generic else {
2248-
spans.push_span_label(param.span, "");
2249-
continue;
2250-
};
2251-
2252-
let mut found_unmatched_generic_params = vec![];
2253-
2254-
for unmatching_idx in idx + 1..params_with_generics.len() {
2255-
if matched_inputs[unmatching_idx.into()].is_none()
2256-
&& let Some(unmatched_idx_param_generic) =
2257-
params_with_generics[unmatching_idx].0
2258-
&& unmatched_idx_param_generic.name.ident() == generic.name.ident()
2259-
{
2260-
found_unmatched_generic_params
2261-
.push(params_with_generics[unmatching_idx].1);
2262-
}
2263-
}
2264-
2265-
if found_unmatched_generic_params.is_empty() {
2266-
spans.push_span_label(param.span, "");
2267-
continue;
2268-
}
2269-
2270-
let generics_idx = generics_map
2271-
.iter()
2272-
.filter(|x| x.1.name.ident() == generic.name.ident())
2273-
.next()
2274-
.map(|x| x.0);
2275-
2276-
let generics_idx = generics_idx.unwrap_or_else(|| {
2277-
let generics_map_len = generics_map.len();
2278-
generics_map.push((generics_map_len, generic));
2279-
generics_map_len
2280-
});
2281-
matched_params_map.push((generics_idx, idx, param));
2282-
if unmatched_params_map.iter().filter(|x| x.0 == generics_idx).count() > 0 {
2283-
// Already processed the unmatched params
2284-
continue;
2285-
}
2286-
for unmatched_param in &found_unmatched_generic_params {
2287-
unmatched_params_map.push((generics_idx, unmatched_param));
2288-
}
2289-
}
2290-
2291-
for (generic_idx, generic) in &generics_map {
2292-
let matched_params: Vec<(usize, &hir::Param<'_>)> = matched_params_map
2293-
.iter()
2294-
.filter(|x| x.0 == *generic_idx)
2295-
.map(|x| (x.1, x.2))
2296-
.collect();
2297-
let unmatched_params: Vec<&hir::Param<'_>> = unmatched_params_map
2298-
.iter()
2299-
.filter(|x| x.0 == *generic_idx)
2300-
.map(|x| x.1)
2301-
.collect();
2240+
for (idx, (generic_param, param)) in
2241+
params_with_generics.iter().enumerate().filter(|(idx, _)| {
2242+
check_for_matched_generics
2243+
|| expected_idx.map_or(true, |expected_idx| expected_idx == *idx)
2244+
})
2245+
{
2246+
// TODO: Must be a better thing we can do here
2247+
let Some(generic_param) = generic_param else {
2248+
spans.push_span_label(param.span, "");
2249+
continue;
2250+
};
23022251

2303-
let all_param_idents: Vec<String> = matched_params
2252+
tracing::debug!(
2253+
"label_fn_like: idx: {:?}, generic_param: {:?}",
2254+
idx,
2255+
matched_inputs
2256+
);
2257+
if matched_inputs[idx.into()].is_none() {
2258+
// If no matching input then we check other params to see if it should have
2259+
// matched, if so we print info about that failure to match.
2260+
let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics
23042261
.iter()
2305-
.map(|x| &x.1)
2306-
.chain(unmatched_params.iter())
2307-
.map(|x| {
2308-
if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind {
2309-
format!("`{ident}`")
2310-
} else {
2311-
"{unknown}".to_string()
2262+
.enumerate()
2263+
.filter(|(other_idx, (other_generic_param, _))| {
2264+
if *other_idx == idx {
2265+
return false;
2266+
}
2267+
let Some(other_generic_param) = other_generic_param else {
2268+
return false;
2269+
};
2270+
if matched_inputs[(*other_idx).into()].is_none() {
2271+
return false;
23122272
}
2273+
other_generic_param.name.ident() == generic_param.name.ident()
23132274
})
2275+
.map(|(other_idx, (_, other_param))| (other_idx, *other_param))
23142276
.collect();
23152277

2316-
spans.push_span_label(
2317-
generic.span,
2318-
format!(
2319-
"{} all reference this parameter {}",
2320-
display_list_with_comma_and(&all_param_idents),
2321-
generic.name.ident().name,
2322-
),
2323-
);
2324-
2325-
for unmatched_param in &unmatched_params {
2326-
let idents: Vec<String> = matched_params
2278+
if other_params_matched.len() > 0 {
2279+
let other_param_matched_names: Vec<String> = other_params_matched
23272280
.iter()
2328-
.map(|x| {
2329-
if let hir::PatKind::Binding(_, _, ident, _) = x.1.pat.kind {
2281+
.map(|(_, other_param)| {
2282+
if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind
2283+
{
23302284
format!("`{ident}`")
23312285
} else {
23322286
"{unknown}".to_string()
23332287
}
23342288
})
23352289
.collect();
23362290

2337-
let matched_ty = matched_params
2338-
.iter()
2339-
.next()
2340-
.map(|x| formal_and_expected_inputs[x.0.into()]);
2341-
2342-
if let Some(matched_ty) = matched_ty {
2343-
let matched_ty =
2344-
self.resolve_vars_if_possible(matched_ty.0).sort_string(self.tcx);
2345-
spans.push_span_label(
2346-
unmatched_param.span,
2347-
format!(
2348-
"this parameter needs to match the {} type of {}",
2349-
matched_ty,
2350-
display_list_with_comma_and(&idents)
2351-
),
2352-
);
2353-
} else {
2354-
spans.push_span_label(
2355-
unmatched_param.span,
2356-
format!(
2357-
"this parameter needs to match the type of {}",
2358-
display_list_with_comma_and(&idents)
2359-
),
2360-
);
2361-
}
2291+
let matched_ty = self
2292+
.resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
2293+
.sort_string(self.tcx);
2294+
2295+
spans.push_span_label(
2296+
param.span,
2297+
format!(
2298+
"this parameter needs to match the {} type of {}",
2299+
matched_ty,
2300+
display_list_with_comma_and(&other_param_matched_names),
2301+
),
2302+
);
2303+
generics_with_unmatched_params.push(generic_param);
2304+
} else {
2305+
spans.push_span_label(param.span, "");
23622306
}
2307+
} else {
2308+
// If we have a matched input then we check other params to see if we have
2309+
// anything unmatched, if so we print info about those unmatched parameters.
2310+
let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics
2311+
.iter()
2312+
.enumerate()
2313+
.filter(|(other_idx, (other_generic_param, _))| {
2314+
if *other_idx == idx {
2315+
return false;
2316+
}
2317+
let Some(other_generic_param) = other_generic_param else {
2318+
return false;
2319+
};
2320+
if matched_inputs[(*other_idx).into()].is_some() {
2321+
return false;
2322+
}
2323+
other_generic_param.name.ident() == generic_param.name.ident()
2324+
})
2325+
.map(|(other_idx, (_, other_param))| (other_idx, *other_param))
2326+
.collect();
23632327

2364-
for (idx, matched_param) in matched_params.iter().enumerate() {
2365-
let idents: Vec<String> = unmatched_params
2328+
if other_params_matched.len() > 0 {
2329+
let other_param_matched_names: Vec<String> = other_params_matched
23662330
.iter()
2367-
.map(|x| {
2368-
if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind {
2331+
.map(|(_, other_param)| {
2332+
if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind
2333+
{
23692334
format!("`{ident}`")
23702335
} else {
23712336
"{unknown}".to_string()
@@ -2374,28 +2339,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23742339
.collect();
23752340

23762341
let matched_ty = self
2377-
.resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].0)
2342+
.resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
23782343
.sort_string(self.tcx);
23792344

23802345
spans.push_span_label(
2381-
matched_param.1.span,
2346+
param.span,
23822347
format!(
23832348
"{} {} to match the {} type of this parameter",
2384-
display_list_with_comma_and(&idents),
2349+
display_list_with_comma_and(&other_param_matched_names),
23852350
format!(
23862351
"need{}",
2387-
pluralize!(if idents.len() == 1 { 0 } else { 1 })
2352+
pluralize!(if other_param_matched_names.len() == 1 {
2353+
0
2354+
} else {
2355+
1
2356+
})
23882357
),
23892358
matched_ty,
23902359
),
23912360
);
2361+
generics_with_unmatched_params.push(generic_param);
2362+
} else {
2363+
spans.push_span_label(param.span, "");
23922364
}
23932365
}
2394-
} else {
2395-
for (_, (_, param)) in params_with_generics.iter().enumerate().filter(|(idx, _)| {
2396-
expected_idx.map_or(true, |expected_idx| expected_idx == *idx)
2397-
}) {
2398-
spans.push_span_label(param.span, "");
2366+
}
2367+
2368+
for generic_param in self
2369+
.tcx
2370+
.hir()
2371+
.get_if_local(def_id)
2372+
.and_then(|node| node.generics())
2373+
.into_iter()
2374+
.flat_map(|x| x.params)
2375+
.filter(|x| {
2376+
generics_with_unmatched_params.iter().any(|y| x.name.ident() == y.name.ident())
2377+
})
2378+
{
2379+
let param_idents_matching: Vec<String> = params_with_generics
2380+
.iter()
2381+
.filter(|(generic, _)| {
2382+
if let Some(generic) = generic {
2383+
generic.name.ident() == generic_param.name.ident()
2384+
} else {
2385+
false
2386+
}
2387+
})
2388+
.map(|(_, param)| {
2389+
if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind {
2390+
format!("`{ident}`")
2391+
} else {
2392+
"{unknown}".to_string()
2393+
}
2394+
})
2395+
.collect();
2396+
2397+
if param_idents_matching.len() > 0 {
2398+
spans.push_span_label(
2399+
generic_param.span,
2400+
format!(
2401+
"{} all reference this parameter {}",
2402+
display_list_with_comma_and(&param_idents_matching),
2403+
generic_param.name.ident().name,
2404+
),
2405+
);
23992406
}
24002407
}
24012408

tests/ui/async-await/coroutine-desc.stderr

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | fun(async {}, async {});
55
| --- -------- ^^^^^^^^ expected `async` block, found a different `async` block
66
| | |
77
| | the expected `async` block
8-
| | expected argument `f2` to be an `async` block because that argument needs to match the type of this parameter
8+
| | expected some other arguments to be an `async` block to match the type of this parameter
99
| arguments to this function are incorrect
1010
|
1111
= note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}`
@@ -14,10 +14,9 @@ note: function defined here
1414
--> $DIR/coroutine-desc.rs:8:4
1515
|
1616
LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
17-
| ^^^ - ----- -----
18-
| | | |
19-
| | | this parameter needs to match the `async` block type of `f1`
20-
| | `f2` needs to match the type of this parameter
17+
| ^^^ - ----- ----- this parameter needs to match the `async` block type of `f1`
18+
| | |
19+
| | `f2` needs to match the `async` block type of this parameter
2120
| `f1` and `f2` all reference this parameter F
2221

2322
error[E0308]: mismatched types
@@ -26,7 +25,7 @@ error[E0308]: mismatched types
2625
LL | fun(one(), two());
2726
| --- ----- ^^^^^ expected future, found a different future
2827
| | |
29-
| | expected argument `f2` to be a future because that argument needs to match the type of this parameter
28+
| | expected some other arguments to be a future to match the type of this parameter
3029
| arguments to this function are incorrect
3130
|
3231
= help: consider `await`ing on both `Future`s
@@ -35,10 +34,9 @@ note: function defined here
3534
--> $DIR/coroutine-desc.rs:8:4
3635
|
3736
LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
38-
| ^^^ - ----- -----
39-
| | | |
40-
| | | this parameter needs to match the future type of `f1`
41-
| | `f2` needs to match the type of this parameter
37+
| ^^^ - ----- ----- this parameter needs to match the future type of `f1`
38+
| | |
39+
| | `f2` needs to match the future type of this parameter
4240
| `f1` and `f2` all reference this parameter F
4341

4442
error[E0308]: mismatched types
@@ -48,7 +46,7 @@ LL | fun((async || {})(), (async || {})());
4846
| --- --------------- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
4947
| | | |
5048
| | | the expected `async` closure body
51-
| | expected argument `f2` to be an `async` closure body because that argument needs to match the type of this parameter
49+
| | expected some other arguments to be an `async` closure body to match the type of this parameter
5250
| arguments to this function are incorrect
5351
|
5452
= note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}`
@@ -57,10 +55,9 @@ note: function defined here
5755
--> $DIR/coroutine-desc.rs:8:4
5856
|
5957
LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
60-
| ^^^ - ----- -----
61-
| | | |
62-
| | | this parameter needs to match the `async` closure body type of `f1`
63-
| | `f2` needs to match the type of this parameter
58+
| ^^^ - ----- ----- this parameter needs to match the `async` closure body type of `f1`
59+
| | |
60+
| | `f2` needs to match the `async` closure body type of this parameter
6461
| `f1` and `f2` all reference this parameter F
6562

6663
error: aborting due to 3 previous errors

0 commit comments

Comments
 (0)