Tweak unsatisfied HRTB errors
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 b4fb018..19bd38b 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 @@
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 @@
expected_has_vid,
actual_has_vid,
any_self_ty_has_vid,
+ leading_ellipsis,
);
err
@@ -318,6 +324,7 @@
expected_has_vid: Option<usize>,
actual_has_vid: Option<usize>,
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 @@
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 @@
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 @@
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 92f92e2..dab4d34 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 0000000..04e2ddd
--- /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::<FooS>(&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 0000000..e698584
--- /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::<FooS>(&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 77a5491..003f326 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 e7deca7..c0e3fd3 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<Self::Item>;
+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<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`
- = note: but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for some specific lifetime `'1`
+ = note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`...
+ = note: ...but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, 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 8614d86..1cfd93e 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 b9920a1..c42297c 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<Self::Item>;
}
@@ -109,6 +109,7 @@
//[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 9863761..3ed2779 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 | <u32 as RefFoo<u32>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | | fn foo(self) -> &'x T;
+LL | | }
+ | |_- trait `Foo` defined here
+...
+LL | <u32 as RefFoo<u32>>::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 | <i32 as RefFoo<i32>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | | fn foo(self) -> &'x T;
+LL | | }
+ | |_- trait `Foo` defined here
+...
+LL | <i32 as RefFoo<i32>>::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 | <u64 as RefFoo<u64>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | | fn foo(self) -> &'x T;
+LL | | }
+ | |_- trait `Foo` defined here
+...
+LL | <u64 as RefFoo<u64>>::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 | <i64 as RefFoo<i64>>::ref_foo(a)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<'x, T> {
+LL | | fn foo(self) -> &'x T;
+LL | | }
+ | |_- trait `Foo` defined here
+...
+LL | <i64 as RefFoo<i64>>::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 c6d0805..1b3f57b 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 f25e18e..f44c842 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<Source> {
+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