about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs29
-rw-r--r--src/test/ui/argument-suggestions/formal-and-expected-differ.rs25
-rw-r--r--src/test/ui/argument-suggestions/formal-and-expected-differ.stderr30
4 files changed, 77 insertions, 11 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index be618eb664c..9ca7730daa6 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -30,6 +30,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
         error: Option<TypeError<'tcx>>,
     ) {
+        if expr_ty == expected {
+            return;
+        }
+
         self.annotate_expected_due_to_let_ty(err, expr, error);
 
         // Use `||` to give these suggestions a precedence
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index a7a60a19bd3..8cf70eb5431 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -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.
         // 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
@@ -661,10 +673,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // A tuple wrap suggestion actually occurs within,
                         // so don't do anything special here.
                         err = self.err_ctxt().report_and_explain_type_error(
-                            TypeTrace::types(
-                                &self.misc(*lo),
-                                true,
-                                formal_and_expected_inputs[mismatch_idx.into()].1,
+                            mk_trace(
+                                *lo,
+                                formal_and_expected_inputs[mismatch_idx.into()],
                                 provided_arg_tys[mismatch_idx.into()].0,
                             ),
                             terr,
@@ -748,9 +759,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         errors.drain_filter(|error| {
                 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 (expected_ty, _) = formal_and_expected_inputs[*expected_idx];
-                let cause = &self.misc(provided_span);
-                let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+                let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
                 if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
                     self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
                     return true;
@@ -774,8 +783,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         {
             let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
             let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
-            let cause = &self.misc(provided_arg_span);
-            let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+            let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
             let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
             self.emit_coerce_suggestions(
                 &mut err,
@@ -847,8 +855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
                     let (provided_ty, provided_span) = provided_arg_tys[provided_idx];
                     if let Compatibility::Incompatible(error) = compatibility {
-                        let cause = &self.misc(provided_span);
-                        let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+                        let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
                         if let Some(e) = error {
                             self.err_ctxt().note_type_err(
                                 &mut err,
diff --git a/src/test/ui/argument-suggestions/formal-and-expected-differ.rs b/src/test/ui/argument-suggestions/formal-and-expected-differ.rs
new file mode 100644
index 00000000000..5e3b55ca525
--- /dev/null
+++ b/src/test/ui/argument-suggestions/formal-and-expected-differ.rs
@@ -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
+}
diff --git a/src/test/ui/argument-suggestions/formal-and-expected-differ.stderr b/src/test/ui/argument-suggestions/formal-and-expected-differ.stderr
new file mode 100644
index 00000000000..905875b5277
--- /dev/null
+++ b/src/test/ui/argument-suggestions/formal-and-expected-differ.stderr
@@ -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`.