about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2024-08-06 18:18:15 -0700
committerMichael Howell <michael@notriddle.com>2024-08-06 18:24:17 -0700
commit20c833c632d76ee78284441226f12b919318bc4b (patch)
tree50a707aee18f62580856f65cd7525ba743ddd787
parent1b587a6e76200fdd8364ef910246efa11c973e7b (diff)
downloadrust-20c833c632d76ee78284441226f12b919318bc4b.tar.gz
rust-20c833c632d76ee78284441226f12b919318bc4b.zip
diagnostics: `Box<dyn Trait>` suggestion with multiple matching impl
The two altered expectation messages both seem like improvements:

- `coerce-expect-unsized-ascribed.stderr` says you can go
  `Box<char> -> Box<dyn Debug>`, which you can.
- `upcast_soundness_bug.stderr` used to say that you could go
  `Box<dyn Trait<u8, u8>> -> Box<dyn Trait>`, which you can't,
  because the type parameters are missing in the destination
  and the only ones that work aren't what's needed.
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs24
-rw-r--r--tests/ui/coercion/coerce-expect-unsized-ascribed.stderr4
-rw-r--r--tests/ui/traits/upcast_soundness_bug.stderr1
3 files changed, 13 insertions, 16 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index 864510bb650..0c140f93d94 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -313,11 +313,9 @@ impl<T> Trait<T> for X {
                     (ty::Dynamic(t, _, ty::DynKind::Dyn), _)
                         if let Some(def_id) = t.principal_def_id() =>
                     {
-                        let mut impl_def_ids = vec![];
-                        tcx.for_each_relevant_impl(def_id, values.found, |did| {
-                            impl_def_ids.push(did)
-                        });
-                        if let [_] = &impl_def_ids[..] {
+                        let has_non_blanket_impl =
+                            tcx.non_blanket_impls_for_ty(def_id, values.found).next().is_some();
+                        if has_non_blanket_impl {
                             let trait_name = tcx.item_name(def_id);
                             diag.help(format!(
                                 "`{}` implements `{trait_name}` so you could box the found value \
@@ -330,11 +328,9 @@ impl<T> Trait<T> for X {
                     (_, ty::Dynamic(t, _, ty::DynKind::Dyn))
                         if let Some(def_id) = t.principal_def_id() =>
                     {
-                        let mut impl_def_ids = vec![];
-                        tcx.for_each_relevant_impl(def_id, values.expected, |did| {
-                            impl_def_ids.push(did)
-                        });
-                        if let [_] = &impl_def_ids[..] {
+                        let has_non_blanket_impl =
+                            tcx.non_blanket_impls_for_ty(def_id, values.expected).next().is_some();
+                        if has_non_blanket_impl {
                             let trait_name = tcx.item_name(def_id);
                             diag.help(format!(
                                 "`{}` implements `{trait_name}` so you could change the expected \
@@ -346,11 +342,9 @@ impl<T> Trait<T> for X {
                     (ty::Dynamic(t, _, ty::DynKind::DynStar), _)
                         if let Some(def_id) = t.principal_def_id() =>
                     {
-                        let mut impl_def_ids = vec![];
-                        tcx.for_each_relevant_impl(def_id, values.found, |did| {
-                            impl_def_ids.push(did)
-                        });
-                        if let [_] = &impl_def_ids[..] {
+                        let has_non_blanket_impl =
+                            tcx.non_blanket_impls_for_ty(def_id, values.found).next().is_some();
+                        if has_non_blanket_impl {
                             let trait_name = tcx.item_name(def_id);
                             diag.help(format!(
                                 "`{}` implements `{trait_name}`, `#[feature(dyn_star)]` is likely \
diff --git a/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr b/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr
index 646044ae41a..0c220a13876 100644
--- a/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr
+++ b/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr
@@ -42,6 +42,7 @@ LL |     let _ = type_ascribe!(Box::new( if true { false } else { true }), Box<d
    |
    = note: expected struct `Box<dyn Debug>`
               found struct `Box<bool>`
+   = help: `bool` implements `Debug` so you could box the found value and coerce it to the trait object `Box<dyn Debug>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:16:27
@@ -51,6 +52,7 @@ LL |     let _ = type_ascribe!(Box::new( match true { true => 'a', false => 'b'
    |
    = note: expected struct `Box<dyn Debug>`
               found struct `Box<char>`
+   = help: `char` implements `Debug` so you could box the found value and coerce it to the trait object `Box<dyn Debug>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:18:27
@@ -96,6 +98,7 @@ LL |     let _ = type_ascribe!(&if true { false } else { true }, &dyn Debug);
    |
    = note: expected reference `&dyn Debug`
               found reference `&bool`
+   = help: `bool` implements `Debug` so you could box the found value and coerce it to the trait object `Box<dyn Debug>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:24:27
@@ -105,6 +108,7 @@ LL |     let _ = type_ascribe!(&match true { true => 'a', false => 'b' }, &dyn D
    |
    = note: expected reference `&dyn Debug`
               found reference `&char`
+   = help: `char` implements `Debug` so you could box the found value and coerce it to the trait object `Box<dyn Debug>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:26:27
diff --git a/tests/ui/traits/upcast_soundness_bug.stderr b/tests/ui/traits/upcast_soundness_bug.stderr
index 5864abcdb41..31f77b52b5f 100644
--- a/tests/ui/traits/upcast_soundness_bug.stderr
+++ b/tests/ui/traits/upcast_soundness_bug.stderr
@@ -6,7 +6,6 @@ LL |     let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
    |
    = note: expected trait object `dyn Trait<u8, u8>`
               found trait object `dyn Trait<u8, u16>`
-   = help: `dyn Trait<u8, u16>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
 
 error: aborting due to 1 previous error