diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs index b4fb0189206..19bd38b45b3 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -192,23 +192,28 @@ fn try_report_placeholders_trait( vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs ); - let mut err = self.tcx().sess.struct_span_err( - cause.span(self.tcx()), - &format!( - "implementation of `{}` is not general enough", - self.tcx().def_path_str(trait_def_id), - ), + let span = cause.span(self.tcx()); + let msg = format!( + "implementation of `{}` is not general enough", + self.tcx().def_path_str(trait_def_id), + ); + let mut err = self.tcx().sess.struct_span_err(span, &msg); + err.span_label( + self.tcx().def_span(trait_def_id), + format!("trait `{}` defined here", self.tcx().def_path_str(trait_def_id)), ); - match cause.code { - ObligationCauseCode::ItemObligation(def_id) => { - err.note(&format!( - "Due to a where-clause on `{}`,", - self.tcx().def_path_str(def_id), - )); - } - _ => (), - } + let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code { + err.span_label(span, "doesn't satisfy where-clause"); + err.span_label( + self.tcx().def_span(def_id), + &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)), + ); + true + } else { + err.span_label(span, &msg); + false + }; let expected_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef { def_id: trait_def_id, @@ -295,6 +300,7 @@ fn try_report_placeholders_trait( expected_has_vid, actual_has_vid, any_self_ty_has_vid, + leading_ellipsis, ); err @@ -318,6 +324,7 @@ fn explain_actual_impl_that_was_found( expected_has_vid: Option, actual_has_vid: Option, any_self_ty_has_vid: bool, + leading_ellipsis: bool, ) { // HACK(eddyb) maybe move this in a more central location. #[derive(Copy, Clone)] @@ -392,13 +399,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut note = if passive_voice { format!( - "`{}` would have to be implemented for the type `{}`", + "{}`{}` would have to be implemented for the type `{}`", + if leading_ellipsis { "..." } else { "" }, expected_trait_ref, expected_trait_ref.map(|tr| tr.self_ty()), ) } else { format!( - "`{}` must implement `{}`", + "{}`{}` must implement `{}`", + if leading_ellipsis { "..." } else { "" }, expected_trait_ref.map(|tr| tr.self_ty()), expected_trait_ref, ) @@ -407,20 +416,20 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match (has_sub, has_sup) { (Some(n1), Some(n2)) => { let _ = write!(note, - ", for any two lifetimes `'{}` and `'{}`", + ", for any two lifetimes `'{}` and `'{}`...", std::cmp::min(n1, n2), std::cmp::max(n1, n2), ); } (Some(n), _) | (_, Some(n)) => { let _ = write!(note, - ", for any lifetime `'{}`", + ", for any lifetime `'{}`...", n, ); } (None, None) => if let Some(n) = expected_has_vid { let _ = write!(note, - ", for some specific lifetime `'{}`", + ", for some specific lifetime `'{}`...", n, ); }, @@ -439,13 +448,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut note = if passive_voice { format!( - "but `{}` is actually implemented for the type `{}`", + "...but `{}` is actually implemented for the type `{}`", actual_trait_ref, actual_trait_ref.map(|tr| tr.self_ty()), ) } else { format!( - "but `{}` actually implements `{}`", + "...but `{}` actually implements `{}`", actual_trait_ref.map(|tr| tr.self_ty()), actual_trait_ref, ) diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr index 92f92e2a32a..dab4d348ceb 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -1,20 +1,26 @@ error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:30:5 | +LL | auto trait Foo {} + | ----------------- trait `Foo` defined here +... LL | assert_foo(gen); - | ^^^^^^^^^^ + | ^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0` - = note: but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1` + = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`... + = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/auto-trait-regions.rs:48:5 | +LL | auto trait Foo {} + | ----------------- trait `Foo` defined here +... LL | assert_foo(gen); - | ^^^^^^^^^^ + | ^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1` - = note: but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` + = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` error: aborting due to 2 previous errors diff --git a/src/test/ui/hrtb/due-to-where-clause.rs b/src/test/ui/hrtb/due-to-where-clause.rs new file mode 100644 index 00000000000..04e2ddd4a60 --- /dev/null +++ b/src/test/ui/hrtb/due-to-where-clause.rs @@ -0,0 +1,16 @@ +// ignore-compare-mode-nll +// ^ This code works in nll mode. + +fn main() { + test::(&mut 42); //~ ERROR implementation of `Foo` is not general enough +} + +trait Foo<'a> {} + +struct FooS<'a> { + data: &'a mut u32, +} + +impl<'a, 'b: 'a> Foo<'b> for FooS<'a> {} + +fn test<'a, F>(data: &'a mut u32) where F: for<'b> Foo<'b> {} diff --git a/src/test/ui/hrtb/due-to-where-clause.stderr b/src/test/ui/hrtb/due-to-where-clause.stderr new file mode 100644 index 00000000000..e698584bb71 --- /dev/null +++ b/src/test/ui/hrtb/due-to-where-clause.stderr @@ -0,0 +1,17 @@ +error: implementation of `Foo` is not general enough + --> $DIR/due-to-where-clause.rs:5:5 + | +LL | test::(&mut 42); + | ^^^^^^^^^^^^ doesn't satisfy where-clause +... +LL | trait Foo<'a> {} + | ---------------- trait `Foo` defined here +... +LL | fn test<'a, F>(data: &'a mut u32) where F: for<'b> Foo<'b> {} + | ------------------------------------------------------------- due to a where-clause on `test`... + | + = note: ...`FooS<'_>` must implement `Foo<'0>`, for any lifetime `'0`... + = note: ...but `FooS<'_>` actually implements `Foo<'1>`, for some specific lifetime `'1` + +error: aborting due to previous error + diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr index 77a5491cb63..003f3265935 100644 --- a/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr +++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.stderr @@ -1,11 +1,14 @@ error: implementation of `Deserialize` is not general enough --> $DIR/hrtb-cache-issue-54302.rs:19:5 | +LL | trait Deserialize<'de> {} + | ------------------------- trait `Deserialize` defined here +... LL | assert_deserialize_owned::<&'static str>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough | - = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0` - = note: but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1` + = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`... + = note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1` error: aborting due to previous error diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr index e7deca7644b..c0e3fd3cf46 100644 --- a/src/test/ui/hrtb/issue-30786.migrate.stderr +++ b/src/test/ui/hrtb/issue-30786.migrate.stderr @@ -1,11 +1,17 @@ error: implementation of `Stream` is not general enough --> $DIR/issue-30786.rs:108:22 | -LL | let map = source.map(|x: &_| x); - | ^^^ +LL | / pub trait Stream { +LL | | type Item; +LL | | fn next(self) -> Option; +LL | | } + | |_- trait `Stream` defined here +... +LL | let map = source.map(|x: &_| x); + | ^^^ implementation of `Stream` is not general enough | - = note: `Stream` would have to be implemented for the type `&'0 mut Map`, for any lifetime `'0` - = note: but `Stream` is actually implemented for the type `&'1 mut Map`, for some specific lifetime `'1` + = note: `Stream` would have to be implemented for the type `&'0 mut Map`, for any lifetime `'0`... + = note: ...but `Stream` is actually implemented for the type `&'1 mut Map`, for some specific lifetime `'1` error: aborting due to previous error diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr index 8614d86d93a..1cfd93e59d9 100644 --- a/src/test/ui/hrtb/issue-30786.nll.stderr +++ b/src/test/ui/hrtb/issue-30786.nll.stderr @@ -1,11 +1,11 @@ error: higher-ranked subtype error - --> $DIR/issue-30786.rs:112:18 + --> $DIR/issue-30786.rs:113:18 | LL | let filter = map.filter(|x: &_| true); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: higher-ranked subtype error - --> $DIR/issue-30786.rs:114:17 + --> $DIR/issue-30786.rs:115:17 | LL | let count = filter.count(); // Assert that we still have a valid stream. | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/hrtb/issue-30786.rs b/src/test/ui/hrtb/issue-30786.rs index b9920a19504..c42297ca683 100644 --- a/src/test/ui/hrtb/issue-30786.rs +++ b/src/test/ui/hrtb/issue-30786.rs @@ -16,7 +16,7 @@ //[nll]compile-flags: -Z borrowck=mir -pub trait Stream { +pub trait Stream { //[migrate]~ NOTE trait `Stream` defined here type Item; fn next(self) -> Option; } @@ -109,6 +109,7 @@ fn main() { //[migrate]~^ ERROR implementation of `Stream` is not general enough //[migrate]~| NOTE `Stream` would have to be implemented for the type `&'0 mut Map //[migrate]~| NOTE but `Stream` is actually implemented for the type `&'1 + //[migrate]~| NOTE implementation of `Stream` is not general enough let filter = map.filter(|x: &_| true); //[nll]~^ ERROR higher-ranked subtype error let count = filter.count(); // Assert that we still have a valid stream. diff --git a/src/test/ui/issues/issue-54302-cases.stderr b/src/test/ui/issues/issue-54302-cases.stderr index 98637611b79..3ed27791643 100644 --- a/src/test/ui/issues/issue-54302-cases.stderr +++ b/src/test/ui/issues/issue-54302-cases.stderr @@ -1,38 +1,58 @@ error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:63:5 | -LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / trait Foo<'x, T> { +LL | | fn foo(self) -> &'x T; +LL | | } + | |_- trait `Foo` defined here +... +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0` - = note: but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` + = note: `Foo<'static, u32>` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... + = note: ...but `Foo<'_, u32>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:69:5 | -LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / trait Foo<'x, T> { +LL | | fn foo(self) -> &'x T; +LL | | } + | |_- trait `Foo` defined here +... +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0` - = note: but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1` + = note: `Foo<'static, i32>` would have to be implemented for the type `&'0 i32`, for any lifetime `'0`... + = note: ...but `Foo<'_, i32>` is actually implemented for the type `&'1 i32`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:75:5 | -LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / trait Foo<'x, T> { +LL | | fn foo(self) -> &'x T; +LL | | } + | |_- trait `Foo` defined here +... +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0` - = note: but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1` + = note: `Foo<'static, u64>` would have to be implemented for the type `&'0 u64`, for any lifetime `'0`... + = note: ...but `Foo<'_, u64>` is actually implemented for the type `&'1 u64`, for some specific lifetime `'1` error: implementation of `Foo` is not general enough --> $DIR/issue-54302-cases.rs:81:5 | -LL | >::ref_foo(a) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / trait Foo<'x, T> { +LL | | fn foo(self) -> &'x T; +LL | | } + | |_- trait `Foo` defined here +... +LL | >::ref_foo(a) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0` - = note: but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1` + = note: `Foo<'static, i64>` would have to be implemented for the type `&'0 i64`, for any lifetime `'0`... + = note: ...but `Foo<'_, i64>` is actually implemented for the type `&'1 i64`, for some specific lifetime `'1` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-54302.stderr b/src/test/ui/issues/issue-54302.stderr index c6d0805f3ab..1b3f57ba188 100644 --- a/src/test/ui/issues/issue-54302.stderr +++ b/src/test/ui/issues/issue-54302.stderr @@ -1,11 +1,14 @@ error: implementation of `Deserialize` is not general enough --> $DIR/issue-54302.rs:13:5 | +LL | trait Deserialize<'de> {} + | ------------------------- trait `Deserialize` defined here +... LL | assert_deserialize_owned::<&'static str>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough | - = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0` - = note: but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1` + = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`... + = note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-55731.stderr b/src/test/ui/issues/issue-55731.stderr index f25e18e5d90..f44c842187c 100644 --- a/src/test/ui/issues/issue-55731.stderr +++ b/src/test/ui/issues/issue-55731.stderr @@ -1,11 +1,16 @@ error: implementation of `DistributedIteratorMulti` is not general enough --> $DIR/issue-55731.rs:48:5 | -LL | multi(Map { - | ^^^^^ +LL | / trait DistributedIteratorMulti { +LL | | type Item; +LL | | } + | |_- trait `DistributedIteratorMulti` defined here +... +LL | multi(Map { + | ^^^^^ implementation of `DistributedIteratorMulti` is not general enough | - = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0` - = note: but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1` + = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`... + = note: ...but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1` error: aborting due to previous error