about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2023-08-14 11:56:23 +0000
committerEsteban Küber <esteban@kuber.com.ar>2023-10-04 02:04:13 +0000
commit2817ece19c67a182c0b0aae402c0e57c8ed22dab (patch)
tree24b913b9bd9c8b6cc33d14e31d3608953846340a
parent79f38b79147a5fb3c52d1fd1afc571226a77419c (diff)
downloadrust-2817ece19c67a182c0b0aae402c0e57c8ed22dab.tar.gz
rust-2817ece19c67a182c0b0aae402c0e57c8ed22dab.zip
Show more information when multiple `impl` apply
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs23
-rw-r--r--tests/ui/error-codes/E0282.rs1
-rw-r--r--tests/ui/error-codes/E0282.stderr37
-rw-r--r--tests/ui/inference/multiple-impl-apply.rs50
-rw-r--r--tests/ui/inference/multiple-impl-apply.stderr35
-rw-r--r--tests/ui/inference/question-mark-type-infer.rs1
-rw-r--r--tests/ui/inference/question-mark-type-infer.stderr19
7 files changed, 158 insertions, 8 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 9a728b1060f..ae56e3d3d4f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -17,6 +17,7 @@ use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache};
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::specialize::to_pretty_impl_header;
 use crate::traits::NormalizeExt;
+use ambiguity::Ambiguity::*;
 use on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{
@@ -2366,14 +2367,28 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     )
                 };
 
-                let ambiguities = ambiguity::recompute_applicable_impls(
+                let mut ambiguities = ambiguity::recompute_applicable_impls(
                     self.infcx,
                     &obligation.with(self.tcx, trait_ref),
                 );
                 let has_non_region_infer =
                     trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
-                // It doesn't make sense to talk about applicable impls if there are more
-                // than a handful of them.
+                // It doesn't make sense to talk about applicable impls if there are more than a
+                // handful of them. If there are a lot of them, but only a few of them have no type
+                // params, we only show those, as they are more likely to be useful/intended.
+                if ambiguities.len() > 20 {
+                    let infcx = self.infcx;
+                    if !ambiguities.iter().all(|option| match option {
+                        DefId(did) => infcx.fresh_args_for_item(DUMMY_SP, *did).is_empty(),
+                        ParamEnv(_) => true,
+                    }) {
+                        // If not all are blanket impls, we filter blanked impls out.
+                        ambiguities.retain(|option| match option {
+                            DefId(did) => infcx.fresh_args_for_item(DUMMY_SP, *did).is_empty(),
+                            ParamEnv(_) => true,
+                        });
+                    }
+                }
                 if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
                     if self.tainted_by_errors().is_some() && subst.is_none() {
                         // If `subst.is_none()`, then this is probably two param-env
@@ -2392,7 +2407,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     err.note(format!("cannot satisfy `{predicate}`"));
                     let impl_candidates = self
                         .find_similar_impl_candidates(predicate.to_opt_poly_trait_pred().unwrap());
-                    if impl_candidates.len() < 10 {
+                    if impl_candidates.len() < 40 {
                         self.report_similar_impl_candidates(
                             impl_candidates.as_slice(),
                             trait_ref,
diff --git a/tests/ui/error-codes/E0282.rs b/tests/ui/error-codes/E0282.rs
index f1f93b3aed6..a7d8ae2d7f5 100644
--- a/tests/ui/error-codes/E0282.rs
+++ b/tests/ui/error-codes/E0282.rs
@@ -1,4 +1,5 @@
 fn main() {
     let x = "hello".chars().rev().collect();
     //~^ ERROR E0282
+    //~| ERROR E0283
 }
diff --git a/tests/ui/error-codes/E0282.stderr b/tests/ui/error-codes/E0282.stderr
index 892d3a81f27..20d115e1711 100644
--- a/tests/ui/error-codes/E0282.stderr
+++ b/tests/ui/error-codes/E0282.stderr
@@ -9,6 +9,39 @@ help: consider giving `x` an explicit type
 LL |     let x: Vec<_> = "hello".chars().rev().collect();
    |          ++++++++
 
-error: aborting due to previous error
+error[E0283]: type annotations needed
+  --> $DIR/E0282.rs:2:9
+   |
+LL |     let x = "hello".chars().rev().collect();
+   |         ^                         ------- type must be known at this point
+   |
+   = note: multiple `impl`s satisfying `_: FromIterator<char>` found in the following crates: `alloc`, `hashbrown`, `std`:
+           - impl FromIterator<char> for String;
+           - impl<'a, T> FromIterator<T> for Cow<'a, [T]>
+             where T: Clone;
+           - impl<'a> FromIterator<char> for Cow<'a, str>;
+           - impl<I> FromIterator<I> for Box<[I]>;
+           - impl<T, S, A> FromIterator<T> for hashbrown::set::HashSet<T, S, A>
+             where T: Eq, T: Hash, S: BuildHasher, S: Default, A: Default, A: Allocator, A: Clone;
+           - impl<T, S> FromIterator<T> for HashSet<T, S>
+             where T: Eq, T: Hash, S: BuildHasher, S: Default;
+           - impl<T> FromIterator<T> for Arc<[T]>;
+           - impl<T> FromIterator<T> for BTreeSet<T>
+             where T: Ord;
+           - impl<T> FromIterator<T> for BinaryHeap<T>
+             where T: Ord;
+           - impl<T> FromIterator<T> for LinkedList<T>;
+           - impl<T> FromIterator<T> for Rc<[T]>;
+           - impl<T> FromIterator<T> for Vec<T>;
+           - impl<T> FromIterator<T> for VecDeque<T>;
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider giving `x` an explicit type
+   |
+LL |     let x: Vec<_> = "hello".chars().rev().collect();
+   |          ++++++++
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/inference/multiple-impl-apply.rs b/tests/ui/inference/multiple-impl-apply.rs
new file mode 100644
index 00000000000..e6a6b928e56
--- /dev/null
+++ b/tests/ui/inference/multiple-impl-apply.rs
@@ -0,0 +1,50 @@
+struct Foo {
+    inner: u32,
+}
+
+struct Bar {
+    inner: u32,
+}
+
+#[derive(Clone, Copy)]
+struct Baz {
+    inner: u32,
+}
+
+impl From<Baz> for Bar {
+    fn from(other: Baz) -> Self {
+        Self {
+            inner: other.inner,
+        }
+    }
+}
+
+impl From<Baz> for Foo {
+    fn from(other: Baz) -> Self {
+        Self {
+            inner: other.inner,
+        }
+    }
+}
+
+fn main() {
+    let x: Baz = Baz { inner: 42 };
+
+    // DOESN'T Compile: Multiple options!
+    let y = x.into();
+    //~^ ERROR E0282
+    //~| ERROR E0283
+
+    let y_1: Foo = x.into();
+    let y_2: Bar = x.into();
+
+    let z_1 = Foo::from(y_1);
+    let z_2 = Bar::from(y_2);
+
+    // No type annotations needed, the compiler KNOWS the type must be `Foo`!
+    let m = magic_foo(x);
+}
+
+fn magic_foo(arg: Baz) -> Foo {
+    arg.into()
+}
diff --git a/tests/ui/inference/multiple-impl-apply.stderr b/tests/ui/inference/multiple-impl-apply.stderr
new file mode 100644
index 00000000000..47ed4916881
--- /dev/null
+++ b/tests/ui/inference/multiple-impl-apply.stderr
@@ -0,0 +1,35 @@
+error[E0282]: type annotations needed
+  --> $DIR/multiple-impl-apply.rs:34:9
+   |
+LL |     let y = x.into();
+   |         ^
+   |
+help: consider giving `y` an explicit type
+   |
+LL |     let y: /* Type */ = x.into();
+   |          ++++++++++++
+
+error[E0283]: type annotations needed
+  --> $DIR/multiple-impl-apply.rs:34:9
+   |
+LL |     let y = x.into();
+   |         ^     ---- type must be known at this point
+   |
+note: multiple `impl`s satisfying `_: From<Baz>` found
+  --> $DIR/multiple-impl-apply.rs:14:1
+   |
+LL | impl From<Baz> for Bar {
+   | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl From<Baz> for Foo {
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   = note: required for `Baz` to implement `Into<_>`
+help: consider giving `y` an explicit type
+   |
+LL |     let y: /* Type */ = x.into();
+   |          ++++++++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/inference/question-mark-type-infer.rs b/tests/ui/inference/question-mark-type-infer.rs
index 10560f85ed4..ab44c830b03 100644
--- a/tests/ui/inference/question-mark-type-infer.rs
+++ b/tests/ui/inference/question-mark-type-infer.rs
@@ -9,6 +9,7 @@ fn g() -> Result<Vec<i32>, ()> {
     let l = [1, 2, 3, 4];
     l.iter().map(f).collect()?
     //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
 }
 
 fn main() {
diff --git a/tests/ui/inference/question-mark-type-infer.stderr b/tests/ui/inference/question-mark-type-infer.stderr
index 7a1e850d157..e8f040138fe 100644
--- a/tests/ui/inference/question-mark-type-infer.stderr
+++ b/tests/ui/inference/question-mark-type-infer.stderr
@@ -9,6 +9,21 @@ help: consider specifying the generic argument
 LL |     l.iter().map(f).collect::<Vec<_>>()?
    |                            ++++++++++
 
-error: aborting due to previous error
+error[E0283]: type annotations needed
+  --> $DIR/question-mark-type-infer.rs:10:21
+   |
+LL |     l.iter().map(f).collect()?
+   |                     ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect`
+   |
+   = note: cannot satisfy `_: FromIterator<Result<i32, ()>>`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+help: consider specifying the generic argument
+   |
+LL |     l.iter().map(f).collect::<Vec<_>>()?
+   |                            ++++++++++
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.