about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src/traits
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-07-30 20:39:47 +0530
committerGitHub <noreply@github.com>2022-07-30 20:39:47 +0530
commiteb378d2015d10b6b99955512ab005665f417e014 (patch)
treea127271a4e8d242b84f55cebf51d801bc3695e5c /compiler/rustc_trait_selection/src/traits
parentc668820365bc9c66408b993cda84d48532a9e0ce (diff)
parent7da578b8f818cef1957502298f30ff10729278b5 (diff)
downloadrust-eb378d2015d10b6b99955512ab005665f417e014.tar.gz
rust-eb378d2015d10b6b99955512ab005665f417e014.zip
Rollup merge of #99862 - WaffleLapkin:type_mismatch_fix, r=compiler-errors
Improve type mismatch w/ function signatures

This PR makes use of `note: expected/found` (instead of labeling types in labels) in type mismatch with function signatures. Pros: it's easier to compare the signatures, cons: the error is a little more verbose now.

This is especially nice when
- The signatures differ in a small subset of parameters (same parameters are elided)
- The difference is in details, for example `isize` vs `usize` (there is a better chance that the types align)

Also this PR fixes the inconsistency in variable names in the edited code (`expected` and `found`).

A zulip thread from which this pr started: [[link]](https://rust-lang.zulipchat.com/#narrow/stream/147480-t-compiler.2Fwg-diagnostics/topic/Type.20error.20regression.3F.2E.2E.2E/near/289756602).

An example diagnostic:

<table>
<tr>
<th>this pr</th>
<th>nightly</th>
</tr>
<tr>
<td>

```text
error[E0631]: type mismatch in function arguments
  --> ./t.rs:4:12
   |
4  |     expect(&f);
   |     ------ ^^ expected due to this
   |     |
   |     required by a bound introduced by this call
...
10 | fn f(_: isize, _: u8, _: Vec<u32>) {}
   | ---------------------------------- found signature defined here
   |
   = note: expected function signature `fn(usize, _, Vec<u64>) -> _`
              found function signature `fn(isize, _, Vec<u32>) -> _`
note: required because of the requirements on the impl of `Trait` for `fn(isize, u8, Vec<u32>) {f}`
  --> ./t.rs:8:9
   |
8  | impl<F> Trait for F where F: Fn(usize, u8, Vec<u64>) -> u8 {}
   |         ^^^^^     ^
   = note: required for the cast from `fn(isize, u8, Vec<u32>) {f}` to the object type `dyn Trait`
```

</td>
<td>

```text
error[E0631]: type mismatch in function arguments
  --> ./t.rs:4:12
   |
4  |     expect(&f);
   |     ------ ^^ expected signature of `fn(usize, u8, Vec<u64>) -> _`
   |     |
   |     required by a bound introduced by this call
...
10 | fn f(_: isize, _: u8, _: Vec<u32>) {}
   | ---------------------------------- found signature of `fn(isize, u8, Vec<u32>) -> _`
   |
note: required because of the requirements on the impl of `Trait` for `fn(isize, u8, Vec<u32>) {f}`
  --> ./t.rs:8:9
   |
8  | impl<F> Trait for F where F: Fn(usize, u8, Vec<u64>) -> u8 {}
   |         ^^^^^     ^
   = note: required for the cast to the object type `dyn Trait`
```

</td>
</tr>
</table>

<details><summary>code</summary>
<p>

```rust
fn main() {
    fn expect(_: &dyn Trait) {}

    expect(&f);
}

trait Trait {}
impl<F> Trait for F where F: Fn(usize, u8, Vec<u64>) -> u8 {}

fn f(_: isize, _: u8, _: Vec<u32>) {}
```

</p>
</details>

r? `@compiler-errors`
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs33
1 files changed, 20 insertions, 13 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 05a8754af81..b2eb8fdf8a5 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -20,6 +20,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::hir::map;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
@@ -253,8 +254,8 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         span: Span,
         found_span: Option<Span>,
-        expected_ref: ty::PolyTraitRef<'tcx>,
         found: ty::PolyTraitRef<'tcx>,
+        expected: ty::PolyTraitRef<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
 
     fn suggest_fully_qualified_path(
@@ -1536,13 +1537,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         span: Span,
         found_span: Option<Span>,
-        expected_ref: ty::PolyTraitRef<'tcx>,
         found: ty::PolyTraitRef<'tcx>,
+        expected: ty::PolyTraitRef<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        pub(crate) fn build_fn_sig_string<'tcx>(
+        pub(crate) fn build_fn_sig_ty<'tcx>(
             tcx: TyCtxt<'tcx>,
             trait_ref: ty::PolyTraitRef<'tcx>,
-        ) -> String {
+        ) -> Ty<'tcx> {
             let inputs = trait_ref.skip_binder().substs.type_at(1);
             let sig = match inputs.kind() {
                 ty::Tuple(inputs)
@@ -1564,10 +1565,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     abi::Abi::Rust,
                 ),
             };
-            trait_ref.rebind(sig).to_string()
+
+            tcx.mk_fn_ptr(trait_ref.rebind(sig))
         }
 
-        let argument_kind = match expected_ref.skip_binder().self_ty().kind() {
+        let argument_kind = match expected.skip_binder().self_ty().kind() {
             ty::Closure(..) => "closure",
             ty::Generator(..) => "generator",
             _ => "function",
@@ -1576,17 +1578,22 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             self.tcx.sess,
             span,
             E0631,
-            "type mismatch in {} arguments",
-            argument_kind
+            "type mismatch in {argument_kind} arguments",
         );
 
-        let found_str = format!("expected signature of `{}`", build_fn_sig_string(self.tcx, found));
-        err.span_label(span, found_str);
+        err.span_label(span, "expected due to this");
 
         let found_span = found_span.unwrap_or(span);
-        let expected_str =
-            format!("found signature of `{}`", build_fn_sig_string(self.tcx, expected_ref));
-        err.span_label(found_span, expected_str);
+        err.span_label(found_span, "found signature defined here");
+
+        let expected = build_fn_sig_ty(self.tcx, expected);
+        let found = build_fn_sig_ty(self.tcx, found);
+
+        let (expected_str, found_str) =
+            self.tcx.infer_ctxt().enter(|infcx| infcx.cmp(expected, found));
+
+        let signature_kind = format!("{argument_kind} signature");
+        err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
 
         err
     }