Skip to content

Commit fe80364

Browse files
Rollup merge of #104261 - compiler-errors:formal-and-expected-differ, r=estebank
More accurately report error when formal and expected signature types differ Fixes #104242
2 parents 6601e20 + 55f1f99 commit fe80364

File tree

4 files changed

+77
-11
lines changed

4 files changed

+77
-11
lines changed

compiler/rustc_hir_typeck/src/demand.rs

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3030
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
3131
error: Option<TypeError<'tcx>>,
3232
) {
33+
if expr_ty == expected {
34+
return;
35+
}
36+
3337
self.annotate_expected_due_to_let_ty(err, expr, error);
3438

3539
// Use `||` to give these suggestions a precedence

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+18-11
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
597597
}
598598
};
599599

600+
let mk_trace = |span, (formal_ty, expected_ty), provided_ty| {
601+
let mismatched_ty = if expected_ty == provided_ty {
602+
// If expected == provided, then we must have failed to sup
603+
// the formal type. Avoid printing out "expected Ty, found Ty"
604+
// in that case.
605+
formal_ty
606+
} else {
607+
expected_ty
608+
};
609+
TypeTrace::types(&self.misc(span), true, mismatched_ty, provided_ty)
610+
};
611+
600612
// The algorithm here is inspired by levenshtein distance and longest common subsequence.
601613
// We'll try to detect 4 different types of mistakes:
602614
// - An extra parameter has been provided that doesn't satisfy *any* of the other inputs
@@ -661,10 +673,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
661673
// A tuple wrap suggestion actually occurs within,
662674
// so don't do anything special here.
663675
err = self.err_ctxt().report_and_explain_type_error(
664-
TypeTrace::types(
665-
&self.misc(*lo),
666-
true,
667-
formal_and_expected_inputs[mismatch_idx.into()].1,
676+
mk_trace(
677+
*lo,
678+
formal_and_expected_inputs[mismatch_idx.into()],
668679
provided_arg_tys[mismatch_idx.into()].0,
669680
),
670681
terr,
@@ -748,9 +759,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
748759
errors.drain_filter(|error| {
749760
let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = error else { return false };
750761
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
751-
let (expected_ty, _) = formal_and_expected_inputs[*expected_idx];
752-
let cause = &self.misc(provided_span);
753-
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
762+
let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
754763
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
755764
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
756765
return true;
@@ -774,8 +783,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
774783
{
775784
let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
776785
let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
777-
let cause = &self.misc(provided_arg_span);
778-
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
786+
let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
779787
let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
780788
self.emit_coerce_suggestions(
781789
&mut err,
@@ -847,8 +855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
847855
let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
848856
let (provided_ty, provided_span) = provided_arg_tys[provided_idx];
849857
if let Compatibility::Incompatible(error) = compatibility {
850-
let cause = &self.misc(provided_span);
851-
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
858+
let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
852859
if let Some(e) = error {
853860
self.err_ctxt().note_type_err(
854861
&mut err,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
pub trait Foo {
2+
type T;
3+
}
4+
5+
impl Foo for i32 {
6+
type T = f32;
7+
}
8+
9+
pub struct U<T1, T2>(T1, S<T2>)
10+
where
11+
T1: Foo<T = T2>;
12+
13+
pub struct S<T>(T);
14+
15+
fn main() {
16+
// The error message here isn't great -- it has to do with the fact that the
17+
// `expected_inputs_for_expected_output` deduced inputs differs from the inputs
18+
// that we infer from the constraints of the signature.
19+
//
20+
// I am not really sure what the best way of presenting this error message is,
21+
// since right now it just suggests changing `3u32` <=> `3f32` back and forth.
22+
let _: U<_, u32> = U(1, S(3u32));
23+
//~^ ERROR mismatched types
24+
//~| ERROR mismatched types
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/formal-and-expected-differ.rs:22:29
3+
|
4+
LL | let _: U<_, u32> = U(1, S(3u32));
5+
| - ^^^^^^^ expected `f32`, found `u32`
6+
| |
7+
| arguments to this struct are incorrect
8+
|
9+
= note: expected struct `S<f32>`
10+
found struct `S<u32>`
11+
note: tuple struct defined here
12+
--> $DIR/formal-and-expected-differ.rs:9:12
13+
|
14+
LL | pub struct U<T1, T2>(T1, S<T2>)
15+
| ^
16+
17+
error[E0308]: mismatched types
18+
--> $DIR/formal-and-expected-differ.rs:22:24
19+
|
20+
LL | let _: U<_, u32> = U(1, S(3u32));
21+
| --------- ^^^^^^^^^^^^^ expected `u32`, found `f32`
22+
| |
23+
| expected due to this
24+
|
25+
= note: expected struct `U<_, u32>`
26+
found struct `U<i32, f32>`
27+
28+
error: aborting due to 2 previous errors
29+
30+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)