Skip to content

Commit 8f5e567

Browse files
committed
Refactored a few bits:
- Firstly get all the information about generics matching out of the HIR - Secondly the labelling for the function is more coherent now - Lastly a few error message improvements
1 parent 6c13acf commit 8f5e567

File tree

6 files changed

+56
-103
lines changed

6 files changed

+56
-103
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+43-89
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
424424
"expected formal_input_tys to be the same size as expected_input_tys"
425425
);
426426
let formal_and_expected_inputs = IndexVec::from_iter(
427-
formal_input_tys.iter().copied().zip_eq(expected_input_tys.iter().copied()),
427+
formal_input_tys
428+
.iter()
429+
.copied()
430+
.zip_eq(expected_input_tys.iter().copied())
431+
.map(|vars| self.resolve_vars_if_possible(vars)),
428432
);
429433

430434
self.set_tainted_by_errors(self.report_arg_errors(
@@ -639,8 +643,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
639643
}
640644

641645
let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx];
642-
let formal_input_ty = self.resolve_vars_if_possible(formal_input_ty);
643-
let expected_input_ty = self.resolve_vars_if_possible(expected_input_ty);
644646
// If either is an error type, we defy the usual convention and consider them to *not* be
645647
// coercible. This prevents our error message heuristic from trying to pass errors into
646648
// every argument.
@@ -713,7 +715,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
713715
// Do we have as many extra provided arguments as the tuple's length?
714716
// If so, we might have just forgotten to wrap some args in a tuple.
715717
if let Some(ty::Tuple(tys)) =
716-
formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| self.resolve_vars_if_possible(tys.1).kind())
718+
formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind())
717719
// If the tuple is unit, we're not actually wrapping any arguments.
718720
&& !tys.is_empty()
719721
&& provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
@@ -732,7 +734,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
732734
provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()),
733735
),
734736
) {
735-
if !self.can_coerce(provided_ty, self.resolve_vars_if_possible(*expected_ty)) {
737+
if !self.can_coerce(provided_ty, *expected_ty) {
736738
satisfied = false;
737739
break;
738740
}
@@ -751,14 +753,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
751753
if tys.len() == 1 {
752754
// A tuple wrap suggestion actually occurs within,
753755
// so don't do anything special here.
754-
let (formal_ty, expected_ty) =
755-
formal_and_expected_inputs[mismatch_idx.into()];
756-
let formal_ty = self.resolve_vars_if_possible(formal_ty);
757-
let expected_ty = self.resolve_vars_if_possible(expected_ty);
758756
err = self.err_ctxt().report_and_explain_type_error(
759757
mk_trace(
760758
*lo,
761-
(formal_ty, expected_ty),
759+
formal_and_expected_inputs[mismatch_idx.into()],
762760
provided_arg_tys[mismatch_idx.into()].0,
763761
),
764762
terr,
@@ -842,10 +840,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
842840
return true;
843841
};
844842
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
845-
let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
846-
let formal_ty = self.resolve_vars_if_possible(formal_ty);
847-
let expected_ty = self.resolve_vars_if_possible(expected_ty);
848-
let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
843+
let trace =
844+
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
849845
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
850846
let mut err = self.err_ctxt().report_and_explain_type_error(trace, *e);
851847
suggest_confusable(&mut err);
@@ -873,8 +869,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
873869
] = &errors[..]
874870
{
875871
let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
876-
let formal_ty = self.resolve_vars_if_possible(formal_ty);
877-
let expected_ty = self.resolve_vars_if_possible(expected_ty);
878872
let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
879873
let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
880874
let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
@@ -896,6 +890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
896890
&matched_inputs,
897891
&provided_arg_tys,
898892
&formal_and_expected_inputs,
893+
is_method,
899894
);
900895

901896
if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind
@@ -1003,8 +998,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1003998
match error {
1004999
Error::Invalid(provided_idx, expected_idx, compatibility) => {
10051000
let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
1006-
let formal_ty = self.resolve_vars_if_possible(formal_ty);
1007-
let expected_ty = self.resolve_vars_if_possible(expected_ty);
10081001
let (provided_ty, provided_span) = provided_arg_tys[provided_idx];
10091002
if let Compatibility::Incompatible(error) = compatibility {
10101003
let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
@@ -1109,7 +1102,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11091102
match &missing_idxs[..] {
11101103
&[expected_idx] => {
11111104
let (_, input_ty) = formal_and_expected_inputs[expected_idx];
1112-
let input_ty = self.resolve_vars_if_possible(input_ty);
11131105
let span = if let Some((_, arg_span)) =
11141106
provided_arg_tys.get(expected_idx.to_provided_idx())
11151107
{
@@ -1132,10 +1124,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11321124
&[first_idx, second_idx] => {
11331125
let (_, first_expected_ty) = formal_and_expected_inputs[first_idx];
11341126
let (_, second_expected_ty) = formal_and_expected_inputs[second_idx];
1135-
let first_expected_ty =
1136-
self.resolve_vars_if_possible(first_expected_ty);
1137-
let second_expected_ty =
1138-
self.resolve_vars_if_possible(second_expected_ty);
11391127
let span = if let (Some((_, first_span)), Some((_, second_span))) = (
11401128
provided_arg_tys.get(first_idx.to_provided_idx()),
11411129
provided_arg_tys.get(second_idx.to_provided_idx()),
@@ -1162,14 +1150,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11621150
}
11631151
&[first_idx, second_idx, third_idx] => {
11641152
let (_, first_expected_ty) = formal_and_expected_inputs[first_idx];
1165-
let first_expected_ty =
1166-
self.resolve_vars_if_possible(first_expected_ty);
11671153
let (_, second_expected_ty) = formal_and_expected_inputs[second_idx];
1168-
let second_expected_ty =
1169-
self.resolve_vars_if_possible(second_expected_ty);
11701154
let (_, third_expected_ty) = formal_and_expected_inputs[third_idx];
1171-
let third_expected_ty =
1172-
self.resolve_vars_if_possible(third_expected_ty);
11731155
let span = if let (Some((_, first_span)), Some((_, third_span))) = (
11741156
provided_arg_tys.get(first_idx.to_provided_idx()),
11751157
provided_arg_tys.get(third_idx.to_provided_idx()),
@@ -1229,7 +1211,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12291211
) => {
12301212
let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx];
12311213
let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx];
1232-
let first_expected_ty = self.resolve_vars_if_possible(first_expected_ty);
12331214
let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) {
12341215
format!(", found `{first_provided_ty}`")
12351216
} else {
@@ -1242,7 +1223,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12421223

12431224
let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx];
12441225
let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx];
1245-
let second_provided_ty = self.resolve_vars_if_possible(second_provided_ty);
12461226
let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) {
12471227
format!(", found `{second_provided_ty}`")
12481228
} else {
@@ -1261,7 +1241,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12611241
Error::Permutation(args) => {
12621242
for (dst_arg, dest_input) in args {
12631243
let (_, expected_ty) = formal_and_expected_inputs[dst_arg];
1264-
let expected_ty = self.resolve_vars_if_possible(expected_ty);
12651244
let (provided_ty, provided_span) = provided_arg_tys[dest_input];
12661245
let provided_ty_name = if !has_error_or_infer([provided_ty]) {
12671246
format!(", found `{provided_ty}`")
@@ -1288,6 +1267,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12881267
&matched_inputs,
12891268
&provided_arg_tys,
12901269
&formal_and_expected_inputs,
1270+
is_method,
12911271
);
12921272

12931273
// Incorporate the argument changes in the removal suggestion.
@@ -1325,7 +1305,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13251305
// To suggest a multipart suggestion when encountering `foo(1, "")` where the def
13261306
// was `fn foo(())`.
13271307
let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
1328-
let expected_ty = self.resolve_vars_if_possible(expected_ty);
13291308
suggestions.push((*arg_span, ty_to_snippet(expected_ty, expected_idx)));
13301309
}
13311310
}
@@ -1402,7 +1381,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14021381
} else {
14031382
// Propose a placeholder of the correct type
14041383
let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
1405-
let expected_ty = self.resolve_vars_if_possible(expected_ty);
14061384
ty_to_snippet(expected_ty, expected_idx)
14071385
};
14081386
suggestion += &suggestion_text;
@@ -2475,77 +2453,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24752453
matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
24762454
provided_arg_tys: &IndexVec<ProvidedIdx, (Ty<'tcx>, Span)>,
24772455
formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
2456+
is_method: bool,
24782457
) {
24792458
let Some(def_id) = callable_def_id else {
24802459
return;
24812460
};
24822461

2483-
for (matched_idx, matched_arg) in matched_inputs.iter_enumerated() {
2484-
let Some(matched_input) = matched_arg else {
2462+
let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
2463+
2464+
for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() {
2465+
if matched_inputs[idx.into()].is_none() {
2466+
continue;
2467+
}
2468+
2469+
let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else {
24852470
continue;
24862471
};
24872472

2488-
let (_, matched_arg_span) = provided_arg_tys[*matched_input];
2489-
let (matched_formal_ty, _) = formal_and_expected_inputs[matched_idx];
2490-
let ty::Infer(ty::TyVar(a)) = matched_formal_ty.kind() else {
2473+
let Some(generic_param) = generic_param else {
24912474
continue;
24922475
};
24932476

2494-
let mut formal_ty_idxs_matched: Vec<usize> = vec![];
2495-
let mut expected_ty_matched = None;
2496-
for (input_idx, (formal_ty, expected_ty)) in formal_and_expected_inputs
2497-
.iter_enumerated()
2498-
// Only care about args after the matched one we're checking.
2499-
//
2500-
// NB: Incompatible should always come after their matching generics.
2501-
// e.g. if we have a function fn f(a: T, b: T, c: T) and we call it with
2502-
// f(1, 2, 3.0) then the first will force T to be an integer, the second
2503-
// then matches and the third is the incompatible argument.
2504-
.filter(|(idx, _)| *idx > matched_idx)
2505-
{
2506-
if let ty::Infer(ty::TyVar(b)) = formal_ty.kind() {
2507-
if self.root_var(*a) == self.root_var(*b) {
2508-
formal_ty_idxs_matched.push(input_idx.into());
2509-
if expected_ty_matched.is_none() {
2510-
expected_ty_matched = Some(expected_ty);
2511-
}
2477+
let mut idxs_matched: Vec<usize> = vec![];
2478+
for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter(
2479+
|(other_idx, (other_generic_param, _))| {
2480+
if *other_idx == idx {
2481+
return false;
25122482
}
2513-
}
2483+
let Some(other_generic_param) = other_generic_param else {
2484+
return false;
2485+
};
2486+
if matched_inputs[(*other_idx).into()].is_some() {
2487+
return false;
2488+
}
2489+
other_generic_param.name.ident() == generic_param.name.ident()
2490+
},
2491+
) {
2492+
idxs_matched.push(other_idx.into());
25142493
}
25152494

2516-
let Some(expected_ty) = expected_ty_matched else {
2495+
if idxs_matched.len() == 0 {
25172496
continue;
2518-
};
2519-
2520-
let params = self
2521-
.tcx
2522-
.hir()
2523-
.get_if_local(def_id)
2524-
.and_then(|node| node.body_id())
2525-
.into_iter()
2526-
.flat_map(|id| self.tcx.hir().body(id).params);
2527-
2528-
let mut all_pats_matched: Vec<String> = vec![];
2529-
let mut incompatible_pats_matched: Vec<String> = vec![];
2530-
for (idx, param) in params
2531-
.into_iter()
2532-
.enumerate()
2533-
.filter(|(idx, _)| formal_ty_idxs_matched.contains(idx))
2534-
{
2535-
let ident = if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind {
2536-
format!("`{ident}`")
2537-
} else {
2538-
format!("`idx:{idx}`")
2539-
};
2540-
if matched_inputs[idx.into()].is_none() {
2541-
incompatible_pats_matched.push(ident.clone());
2542-
}
2543-
all_pats_matched.push(ident);
25442497
}
25452498

2546-
let expected_display_type =
2547-
self.resolve_vars_if_possible(*expected_ty).sort_string(self.tcx);
2548-
let label = if all_pats_matched.len() == 0 {
2499+
let expected_display_type = self
2500+
.resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
2501+
.sort_string(self.tcx);
2502+
let label = if idxs_matched.len() == params_with_generics.len() - 1 {
25492503
format!(
25502504
"expected all arguments to be {} because they need to match the type of this parameter",
25512505
expected_display_type
@@ -2558,7 +2512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25582512
)
25592513
};
25602514

2561-
err.span_label(matched_arg_span, label);
2515+
err.span_label(*matched_arg_span, label);
25622516
}
25632517
}
25642518

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

+3-3
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 some other arguments to be an `async` block to match the type of this parameter
8+
| | expected all arguments to be `async` block because they need 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}`
@@ -25,7 +25,7 @@ error[E0308]: mismatched types
2525
LL | fun(one(), two());
2626
| --- ----- ^^^^^ expected future, found a different future
2727
| | |
28-
| | expected some other arguments to be a future to match the type of this parameter
28+
| | expected all arguments to be future because they need to match the type of this parameter
2929
| arguments to this function are incorrect
3030
|
3131
= help: consider `await`ing on both `Future`s
@@ -46,7 +46,7 @@ LL | fun((async || {})(), (async || {})());
4646
| --- --------------- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
4747
| | | |
4848
| | | the expected `async` closure body
49-
| | expected some other arguments to be an `async` closure body to match the type of this parameter
49+
| | expected all arguments to be `async` closure body because they need to match the type of this parameter
5050
| arguments to this function are incorrect
5151
|
5252
= note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}`

tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
44
LL | test(&mut 7, &7);
55
| ---- ------ ^^ types differ in mutability
66
| | |
7-
| | expected some other arguments to be an `&mut {integer}` to match the type of this parameter
7+
| | expected all arguments to be `&mut {integer}` because they need to match the type of this parameter
88
| arguments to this function are incorrect
99
|
1010
= note: expected mutable reference `&mut {integer}`

0 commit comments

Comments
 (0)