diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 60f4ca6a8759c..32e7a9535a830 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2460,10 +2460,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; err.span_help(span, msg); } else { + // When more than 5 tuples implement the same trait, the output might be very verbose + // Instead of displaying each of these, we sort the candidates by arity in ascending + // order, then we compute the min and the max arity, ensuring that the arities are + // consecutive (by step of one). If these conditions are met, then the output is shown + // as a range of tuples [tuple_min_arity:tuple_max_arity] + let mut tuple_min_arity = usize::MAX; + let mut tuple_max_arity = 0_usize; + let mut last_arity = None; + let mut all_types_tuples_cont_arity = true; + candidates.sort_by(|(c1, _), (c2, _)| { + if let ty::Tuple(tys1) = c1.self_ty().kind() + && let ty::Tuple(tys2) = c2.self_ty().kind() + { + tys1.len().cmp(&tys2.len()) + } else { + std::cmp::Ordering::Equal + } + }); let candidate_names: Vec = candidates .iter() .map(|(c, _)| { if all_traits_equal { + if all_types_tuples_cont_arity + && let ty::Tuple(tys) = c.self_ty().kind() + && last_arity.map_or(1, |a: usize| a.abs_diff(tys.len())) == 1 + { + last_arity = Some(tys.len()); + if tys.len() > tuple_max_arity { + tuple_max_arity = tys.len(); + } + if tys.len() < tuple_min_arity { + tuple_min_arity = tys.len(); + } + } else { + all_types_tuples_cont_arity = false; + } format!( "\n {}", self.tcx.short_string(c.self_ty(), err.long_ty_path()) @@ -2484,6 +2516,29 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } }) .collect(); + + let details = if all_traits_equal && all_types_tuples_cont_arity { + if tuple_min_arity == 0 { + format!("up to tuples of arity {tuple_max_arity}") + } else { + format!( + "for tuples of arity {tuple_min_arity} up to and including {tuple_max_arity}" + ) + } + } else { + String::new() + }; + let (candidate_names, end) = if all_traits_equal && all_types_tuples_cont_arity { + ( + vec![ + // (T₁, T₂, …, Tₙ) + format!("\n (T\u{2081}, T\u{2082}, …, T\u{2099}) {details}"), + ], + 1, + ) + } else { + (candidate_names, end) + }; let msg = if all_types_equal { format!( "`{}` implements trait `{}`", diff --git a/tests/ui/editions/never-type-fallback-breaking.e2024.stderr b/tests/ui/editions/never-type-fallback-breaking.e2024.stderr index 65be5d90d011c..a88bb52738e9f 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2024.stderr +++ b/tests/ui/editions/never-type-fallback-breaking.e2024.stderr @@ -28,6 +28,7 @@ LL | help(1)?; | ^^^^^^^ the trait `From` is not implemented for `()` | = help: the following other types implement trait `From`: + `(T,)` implements `From<[T; 1]>` `(T, T)` implements `From<[T; 2]>` `(T, T, T)` implements `From<[T; 3]>` `(T, T, T, T)` implements `From<[T; 4]>` @@ -35,7 +36,6 @@ LL | help(1)?; `(T, T, T, T, T, T)` implements `From<[T; 6]>` `(T, T, T, T, T, T, T)` implements `From<[T; 7]>` `(T, T, T, T, T, T, T, T)` implements `From<[T; 8]>` - `(T, T, T, T, T, T, T, T, T)` implements `From<[T; 9]>` and 4 others = note: required for `!` to implement `Into<()>` note: required by a bound in `help` diff --git a/tests/ui/suggestions/multiple_tuples_implement_same_trait_continuous_arities.rs b/tests/ui/suggestions/multiple_tuples_implement_same_trait_continuous_arities.rs new file mode 100644 index 0000000000000..83a3577707364 --- /dev/null +++ b/tests/ui/suggestions/multiple_tuples_implement_same_trait_continuous_arities.rs @@ -0,0 +1,21 @@ +use std::fmt::Debug; + +fn testing_debug(t: T) {} +fn testing_mytrait(t: T) {} + +trait MyTrait {} + +impl MyTrait for (i8,) {} +impl MyTrait for (i8,i8) {} +impl MyTrait for (i8,i8,i8) {} +impl MyTrait for (i8,i8,i8,i8) {} +impl MyTrait for (i8,i8,i8,i8,i8) {} + +struct Foo; + +fn main() { + testing_debug((1, Foo)); + //~^ ERROR `Foo` doesn't implement `Debug` [E0277] + testing_mytrait((1, Foo)); + //~^ ERROR the trait bound `({integer}, Foo): MyTrait` is not satisfied [E0277] +} diff --git a/tests/ui/suggestions/multiple_tuples_implement_same_trait_continuous_arities.stderr b/tests/ui/suggestions/multiple_tuples_implement_same_trait_continuous_arities.stderr new file mode 100644 index 0000000000000..fb9bb2642971a --- /dev/null +++ b/tests/ui/suggestions/multiple_tuples_implement_same_trait_continuous_arities.stderr @@ -0,0 +1,42 @@ +error[E0277]: `Foo` doesn't implement `Debug` + --> $DIR/multiple_tuples_implement_same_trait_continuous_arities.rs:17:23 + | +LL | testing_debug((1, Foo)); + | ------------- ^^^ the trait `Debug` is not implemented for `Foo` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `Debug`: + (T₁, T₂, …, Tₙ) up to tuples of arity 12 + and 5 others + = note: required for `({integer}, Foo)` to implement `Debug` +note: required by a bound in `testing_debug` + --> $DIR/multiple_tuples_implement_same_trait_continuous_arities.rs:3:21 + | +LL | fn testing_debug(t: T) {} + | ^^^^^ required by this bound in `testing_debug` +help: consider annotating `Foo` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | struct Foo; + | + +error[E0277]: the trait bound `({integer}, Foo): MyTrait` is not satisfied + --> $DIR/multiple_tuples_implement_same_trait_continuous_arities.rs:19:21 + | +LL | testing_mytrait((1, Foo)); + | --------------- ^^^^^^^^ the trait `MyTrait` is not implemented for `({integer}, Foo)` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `MyTrait`: + (T₁, T₂, …, Tₙ) for tuples of arity 1 up to and including 5 +note: required by a bound in `testing_mytrait` + --> $DIR/multiple_tuples_implement_same_trait_continuous_arities.rs:4:23 + | +LL | fn testing_mytrait(t: T) {} + | ^^^^^^^ required by this bound in `testing_mytrait` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/suggestions/multiple_tuples_implement_same_trait_discontinuous_arities.rs b/tests/ui/suggestions/multiple_tuples_implement_same_trait_discontinuous_arities.rs new file mode 100644 index 0000000000000..d5d860ceab838 --- /dev/null +++ b/tests/ui/suggestions/multiple_tuples_implement_same_trait_discontinuous_arities.rs @@ -0,0 +1,23 @@ +fn testing_mytrait(t: T) {} +fn testing_anothertrait(t: T) {} + +trait MyTrait {} + +impl MyTrait for (i8,) {} +impl MyTrait for (i8,i8,i8) {} +impl MyTrait for (i8,i8,i8,i8) {} +impl MyTrait for (i8,i8,i8,i8,i8) {} +impl MyTrait for (i8,i8,i8,i8,i8,i8) {} + +trait AnotherTrait {} +impl AnotherTrait for (i8,) {} +impl AnotherTrait for (i8,i8) {} + +struct Foo; + +fn main() { + testing_mytrait((1, Foo)); + //~^ ERROR the trait bound `({integer}, Foo): MyTrait` is not satisfied [E0277] + testing_anothertrait((1, Foo)); + //~^ ERROR the trait bound `({integer}, Foo): AnotherTrait` is not satisfied [E0277] +} diff --git a/tests/ui/suggestions/multiple_tuples_implement_same_trait_discontinuous_arities.stderr b/tests/ui/suggestions/multiple_tuples_implement_same_trait_discontinuous_arities.stderr new file mode 100644 index 0000000000000..1786c2142f677 --- /dev/null +++ b/tests/ui/suggestions/multiple_tuples_implement_same_trait_discontinuous_arities.stderr @@ -0,0 +1,44 @@ +error[E0277]: the trait bound `({integer}, Foo): MyTrait` is not satisfied + --> $DIR/multiple_tuples_implement_same_trait_discontinuous_arities.rs:19:21 + | +LL | testing_mytrait((1, Foo)); + | --------------- ^^^^^^^^ the trait `MyTrait` is not implemented for `({integer}, Foo)` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `MyTrait`: + (i8,) + (i8, i8, i8) + (i8, i8, i8, i8) + (i8, i8, i8, i8, i8) + (i8, i8, i8, i8, i8, i8) +note: required by a bound in `testing_mytrait` + --> $DIR/multiple_tuples_implement_same_trait_discontinuous_arities.rs:1:23 + | +LL | fn testing_mytrait(t: T) {} + | ^^^^^^^ required by this bound in `testing_mytrait` + +error[E0277]: the trait bound `({integer}, Foo): AnotherTrait` is not satisfied + --> $DIR/multiple_tuples_implement_same_trait_discontinuous_arities.rs:21:26 + | +LL | testing_anothertrait((1, Foo)); + | -------------------- ^^^^^^^^ the trait `AnotherTrait` is not implemented for `({integer}, Foo)` + | | + | required by a bound introduced by this call + | +help: the following other types implement trait `AnotherTrait` + --> $DIR/multiple_tuples_implement_same_trait_discontinuous_arities.rs:13:1 + | +LL | impl AnotherTrait for (i8,) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(i8,)` +LL | impl AnotherTrait for (i8,i8) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(i8, i8)` +note: required by a bound in `testing_anothertrait` + --> $DIR/multiple_tuples_implement_same_trait_discontinuous_arities.rs:2:28 + | +LL | fn testing_anothertrait(t: T) {} + | ^^^^^^^^^^^^ required by this bound in `testing_anothertrait` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/reservation-impl-ice.stderr b/tests/ui/traits/const-traits/reservation-impl-ice.stderr index d30c014d63f11..125a4710693cc 100644 --- a/tests/ui/traits/const-traits/reservation-impl-ice.stderr +++ b/tests/ui/traits/const-traits/reservation-impl-ice.stderr @@ -5,6 +5,7 @@ LL | impls_from::<()>(); | ^^ the trait `From` is not implemented for `()` | = help: the following other types implement trait `From`: + `(T,)` implements `From<[T; 1]>` `(T, T)` implements `From<[T; 2]>` `(T, T, T)` implements `From<[T; 3]>` `(T, T, T, T)` implements `From<[T; 4]>` @@ -12,7 +13,6 @@ LL | impls_from::<()>(); `(T, T, T, T, T, T)` implements `From<[T; 6]>` `(T, T, T, T, T, T, T)` implements `From<[T; 7]>` `(T, T, T, T, T, T, T, T)` implements `From<[T; 8]>` - `(T, T, T, T, T, T, T, T, T)` implements `From<[T; 9]>` and 4 others note: required by a bound in `impls_from` --> $DIR/reservation-impl-ice.rs:4:24 diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr index 20454e12de558..f5055e05c7cd3 100644 --- a/tests/ui/try-trait/issue-32709.stderr +++ b/tests/ui/try-trait/issue-32709.stderr @@ -10,6 +10,7 @@ LL | Err(5)?; | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: + `(T,)` implements `From<[T; 1]>` `(T, T)` implements `From<[T; 2]>` `(T, T, T)` implements `From<[T; 3]>` `(T, T, T, T)` implements `From<[T; 4]>` @@ -17,7 +18,6 @@ LL | Err(5)?; `(T, T, T, T, T, T)` implements `From<[T; 6]>` `(T, T, T, T, T, T, T)` implements `From<[T; 7]>` `(T, T, T, T, T, T, T, T)` implements `From<[T; 8]>` - `(T, T, T, T, T, T, T, T, T)` implements `From<[T; 9]>` and 4 others error: aborting due to 1 previous error