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` found in the following crates: `alloc`, `hashbrown`, `std`: + - impl FromIterator for String; + - impl<'a, T> FromIterator for Cow<'a, [T]> + where T: Clone; + - impl<'a> FromIterator for Cow<'a, str>; + - impl FromIterator for Box<[I]>; + - impl FromIterator for hashbrown::set::HashSet + where T: Eq, T: Hash, S: BuildHasher, S: Default, A: Default, A: Allocator, A: Clone; + - impl FromIterator for HashSet + where T: Eq, T: Hash, S: BuildHasher, S: Default; + - impl FromIterator for Arc<[T]>; + - impl FromIterator for BTreeSet + where T: Ord; + - impl FromIterator for BinaryHeap + where T: Ord; + - impl FromIterator for LinkedList; + - impl FromIterator for Rc<[T]>; + - impl FromIterator for Vec; + - impl FromIterator for VecDeque; +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(); + | ++++++++ -For more information about this error, try `rustc --explain E0282`. +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/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 for Bar { + fn from(other: Baz) -> Self { + Self { + inner: other.inner, + } + } +} + +impl From 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` found + --> $DIR/multiple-impl-apply.rs:14:1 + | +LL | impl From for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^ +... +LL | impl From 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, ()> { 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::>()? | ++++++++++ -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>` +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::>()? + | ++++++++++ -For more information about this error, try `rustc --explain E0282`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0282, E0283. +For more information about an error, try `rustc --explain E0282`.