More accurately report error when formal and expected signature types differ

This commit is contained in:
Michael Goulet 2022-11-10 20:20:25 +00:00
parent 312d6b8e9a
commit 55f1f993ff
3 changed files with 73 additions and 11 deletions

View File

@ -597,6 +597,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
}; };
let mk_trace = |span, (formal_ty, expected_ty), provided_ty| {
let mismatched_ty = if expected_ty == provided_ty {
// If expected == provided, then we must have failed to sup
// the formal type. Avoid printing out "expected Ty, found Ty"
// in that case.
formal_ty
} else {
expected_ty
};
TypeTrace::types(&self.misc(span), true, mismatched_ty, provided_ty)
};
// The algorithm here is inspired by levenshtein distance and longest common subsequence. // The algorithm here is inspired by levenshtein distance and longest common subsequence.
// We'll try to detect 4 different types of mistakes: // We'll try to detect 4 different types of mistakes:
// - An extra parameter has been provided that doesn't satisfy *any* of the other inputs // - 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> {
// A tuple wrap suggestion actually occurs within, // A tuple wrap suggestion actually occurs within,
// so don't do anything special here. // so don't do anything special here.
err = self.err_ctxt().report_and_explain_type_error( err = self.err_ctxt().report_and_explain_type_error(
TypeTrace::types( mk_trace(
&self.misc(*lo), *lo,
true, formal_and_expected_inputs[mismatch_idx.into()],
formal_and_expected_inputs[mismatch_idx.into()].1,
provided_arg_tys[mismatch_idx.into()].0, provided_arg_tys[mismatch_idx.into()].0,
), ),
terr, terr,
@ -748,9 +759,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
errors.drain_filter(|error| { errors.drain_filter(|error| {
let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = error else { return false }; let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = error else { return false };
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
let (expected_ty, _) = formal_and_expected_inputs[*expected_idx]; let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
let cause = &self.misc(provided_span);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) { if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
self.err_ctxt().report_and_explain_type_error(trace, *e).emit(); self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
return true; return true;
@ -774,8 +783,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{ {
let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
let cause = &self.misc(provided_arg_span); let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err); let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
self.emit_coerce_suggestions( self.emit_coerce_suggestions(
&mut err, &mut err,
@ -847,8 +855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; let (provided_ty, provided_span) = provided_arg_tys[provided_idx];
if let Compatibility::Incompatible(error) = compatibility { if let Compatibility::Incompatible(error) = compatibility {
let cause = &self.misc(provided_span); let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
if let Some(e) = error { if let Some(e) = error {
self.err_ctxt().note_type_err( self.err_ctxt().note_type_err(
&mut err, &mut err,

View File

@ -0,0 +1,25 @@
pub trait Foo {
type T;
}
impl Foo for i32 {
type T = f32;
}
pub struct U<T1, T2>(T1, S<T2>)
where
T1: Foo<T = T2>;
pub struct S<T>(T);
fn main() {
// The error message here isn't great -- it has to do with the fact that the
// `expected_inputs_for_expected_output` deduced inputs differs from the inputs
// that we infer from the constraints of the signature.
//
// I am not really sure what the best way of presenting this error message is,
// since right now it just suggests changing `3u32` <=> `3f32` back and forth.
let _: U<_, u32> = U(1, S(3u32));
//~^ ERROR mismatched types
//~| ERROR mismatched types
}

View File

@ -0,0 +1,30 @@
error[E0308]: mismatched types
--> $DIR/formal-and-expected-differ.rs:22:29
|
LL | let _: U<_, u32> = U(1, S(3u32));
| - ^^^^^^^ expected `f32`, found `u32`
| |
| arguments to this struct are incorrect
|
= note: expected struct `S<f32>`
found struct `S<u32>`
note: tuple struct defined here
--> $DIR/formal-and-expected-differ.rs:9:12
|
LL | pub struct U<T1, T2>(T1, S<T2>)
| ^
error[E0308]: mismatched types
--> $DIR/formal-and-expected-differ.rs:22:24
|
LL | let _: U<_, u32> = U(1, S(3u32));
| --------- ^^^^^^^^^^^^^ expected `u32`, found `f32`
| |
| expected due to this
|
= note: expected struct `U<_, u32>`
found struct `U<i32, f32>`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.