From 190589f8a732393047bd0dc10b27a9aae4410944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 7 Oct 2019 14:23:56 -0700 Subject: [PATCH 01/16] Use structured suggestion for restricting bounds When a trait bound is not met and restricting a type parameter would make the restriction hold, use a structured suggestion pointing at an appropriate place (type param in param list or `where` clause). Account for opaque parameters where instead of suggesting extending the `where` clause, we suggest appending the new restriction: `fn foo(impl Trait + UnmetTrait)`. --- src/librustc/traits/error_reporting.rs | 97 ++++++++++++++++++- ...iated-const-type-parameter-arrays-2.stderr | 4 +- ...ociated-const-type-parameter-arrays.stderr | 4 +- ...types-invalid-trait-ref-issue-18865.stderr | 4 +- .../ui/bad/bad-method-typaram-kind.stderr | 3 +- .../ui/closures/closure-bounds-subtype.stderr | 4 +- .../dst/dst-object-from-unsized-type.stderr | 6 +- ...igher-ranker-supertraits-transitive.stderr | 5 +- .../hrtb-higher-ranker-supertraits.stderr | 10 +- .../ui/kindck/kindck-impl-type-params.stderr | 16 ++- src/test/ui/phantom-oibit.stderr | 8 +- .../ui/suggestions/restrict-type-argument.rs | 31 ++++++ .../suggestions/restrict-type-argument.stderr | 83 ++++++++++++++++ .../traits/trait-suggest-where-clause.stderr | 8 +- .../traits-repeated-supertrait-ambig.stderr | 8 +- .../generic_underconstrained.stderr | 4 +- .../generic_underconstrained2.stderr | 8 +- ...ypeck-default-trait-impl-send-param.stderr | 3 +- .../ui/unsized/unsized-bare-typaram.stderr | 5 +- src/test/ui/unsized/unsized-enum.stderr | 5 +- src/test/ui/unsized/unsized-struct.stderr | 10 +- src/test/ui/unsized3.stderr | 18 ++-- src/test/ui/unsized6.stderr | 51 +++++++--- .../wf/wf-impl-associated-type-trait.stderr | 4 +- ...f-inherent-impl-method-where-clause.stderr | 4 +- 25 files changed, 335 insertions(+), 68 deletions(-) create mode 100644 src/test/ui/suggestions/restrict-type-argument.rs create mode 100644 src/test/ui/suggestions/restrict-type-argument.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 9eb91569ed5c4..b7c7fd4729f0a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -715,8 +715,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // these notes will often be of the form // "the type `T` can't be frobnicated" // which is somewhat confusing. - err.help(&format!("consider adding a `where {}` bound", - trait_ref.to_predicate())); + self.suggest_restricting_param_bound( + &mut err, + &trait_ref, + obligation.cause.body_id, + ); } else { if !have_alt_message { // Can't show anything else useful, try to find similar impls. @@ -960,6 +963,96 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.emit(); } + fn suggest_restricting_param_bound( + &self, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::PolyTraitRef<'_>, + body_id: hir::HirId, + ) { + let node = self.tcx.hir().find(self.tcx.hir().get_parent_item(body_id)); + if let ty::Param(param_ty) = &trait_ref.self_ty().kind { + let restrict_msg = "consider further restricting this bound"; + let param_name = param_ty.name.as_str(); + + if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Struct(_, generics), span, .. + })) | + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Enum(_, generics), span, .. + })) | + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Union(_, generics), span, .. + })) | + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Trait(_, _, generics, ..), span, .. + })) | + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(_, _, _, generics, ..), span, .. + })) | + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(_, _, generics, _), span, .. + })) = &node { + for param in &generics.params { + if param_name == param.name.ident().as_str() { + if param_name.starts_with("impl ") { + err.span_suggestion( + param.span, + restrict_msg, + // `impl CurrentTrait + MissingTrait` + format!("{} + {}", param.name.ident(), trait_ref), + Applicability::MachineApplicable, + ); + } else { + if generics.where_clause.predicates.is_empty() && + param.bounds.is_empty() + { + err.span_suggestion( + param.span, + "consider restricting this bound", + format!("{}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } else if !generics.where_clause.predicates.is_empty() { + err.span_suggestion( + generics.where_clause.span().unwrap().shrink_to_hi(), + &format!( + "consider further restricting type parameter `{}`", + param_ty, + ), + format!(", {}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } else { + let sp = param.span.with_hi(span.hi()); + let span = self.tcx.sess.source_map().span_through_char(sp, ':'); + if sp != param.span && sp != span { + // Only suggest if we have high certainty that the span covers + // the colon in `foo`. + err.span_suggestion(span, restrict_msg, format!( + "{} + ", + trait_ref.to_predicate(), + ), Applicability::MachineApplicable); + } else { + err.span_label(param.span, &format!( + "consider adding a `where {}` bound", + trait_ref.to_predicate(), + )); + } + } + } + return; + } + } + } + } + // FIXME: Add special check for `?Sized` so we don't suggest `T: Sized + ?Sized`. + + // Fallback in case we didn't find the type argument. Can happen on associated types + // bounds and when `Self` needs to be restricted, like in the ui test + // `associated-types-projection-to-unrelated-trait-in-method-without-default.rs`. + err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); + } + /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a /// suggestion to borrow the initializer in order to use have a slice instead. fn suggest_borrow_on_unsized_slice( diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr index 30b6b4f3909b2..c258892057bf2 100644 --- a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr +++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr @@ -4,10 +4,10 @@ error[E0277]: the trait bound `A: Foo` is not satisfied LL | const Y: usize; | --------------- required by `Foo::Y` ... +LL | pub fn test() { + | -- help: consider further restricting this bound: `A: Foo +` LL | let _array = [4; ::Y]; | ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A` - | - = help: consider adding a `where A: Foo` bound error: aborting due to previous error diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr index 30fa9891a13e1..f6c8e99e27a81 100644 --- a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr +++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr @@ -4,10 +4,10 @@ error[E0277]: the trait bound `A: Foo` is not satisfied LL | const Y: usize; | --------------- required by `Foo::Y` ... +LL | pub fn test() { + | -- help: consider further restricting this bound: `A: Foo +` LL | let _array: [u32; ::Y]; | ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A` - | - = help: consider adding a `where A: Foo` bound error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr b/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr index 01f66a18d25bd..0b8b7fab1359f 100644 --- a/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr +++ b/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr @@ -1,10 +1,10 @@ error[E0277]: the trait bound `T: Foo` is not satisfied --> $DIR/associated-types-invalid-trait-ref-issue-18865.rs:10:12 | +LL | fn f>(t: &T) { + | -- help: consider further restricting this bound: `T: Foo +` LL | let u: >::Bar = t.get_bar(); | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `T` - | - = help: consider adding a `where T: Foo` bound error: aborting due to previous error diff --git a/src/test/ui/bad/bad-method-typaram-kind.stderr b/src/test/ui/bad/bad-method-typaram-kind.stderr index c72b965236006..740667f146680 100644 --- a/src/test/ui/bad/bad-method-typaram-kind.stderr +++ b/src/test/ui/bad/bad-method-typaram-kind.stderr @@ -1,11 +1,12 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/bad-method-typaram-kind.rs:2:7 | +LL | fn foo() { + | -- help: consider further restricting this bound: `T: std::marker::Send +` LL | 1.bar::(); | ^^^ `T` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `T` - = help: consider adding a `where T: std::marker::Send` bound error: aborting due to previous error diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr index 4b703eded69c3..05d5bb1e8d5a8 100644 --- a/src/test/ui/closures/closure-bounds-subtype.stderr +++ b/src/test/ui/closures/closure-bounds-subtype.stderr @@ -4,11 +4,13 @@ error[E0277]: `F` cannot be shared between threads safely LL | fn take_const_owned(_: F) where F: FnOnce() + Sync + Send { | ---------------- ---- required by this bound in `take_const_owned` ... +LL | fn give_owned(f: F) where F: FnOnce() + Send { + | - help: consider further restricting type parameter `F`: `, F: std::marker::Sync` +LL | take_any(f); LL | take_const_owned(f); | ^ `F` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `F` - = help: consider adding a `where F: std::marker::Sync` bound error: aborting due to previous error diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr index 55ac625fc985b..40db575eabd38 100644 --- a/src/test/ui/dst/dst-object-from-unsized-type.stderr +++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr @@ -1,23 +1,25 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/dst-object-from-unsized-type.rs:8:23 | +LL | fn test1(t: &T) { + | -- help: consider further restricting this bound: `T: std::marker::Sized +` LL | let u: &dyn Foo = t; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit - = help: consider adding a `where T: std::marker::Sized` bound = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/dst-object-from-unsized-type.rs:13:23 | +LL | fn test2(t: &T) { + | -- help: consider further restricting this bound: `T: std::marker::Sized +` LL | let v: &dyn Foo = t as &dyn Foo; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit - = help: consider adding a `where T: std::marker::Sized` bound = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr index c2cc8ebad2726..afcb467ad4711 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr @@ -6,10 +6,11 @@ LL | fn want_bar_for_any_ccx(b: &B) LL | where B : for<'ccx> Bar<'ccx> | ------------------- required by this bound in `want_bar_for_any_ccx` ... +LL | where B : Qux + | - help: consider further restricting type parameter `B`: `, for<'ccx> B: Bar<'ccx>` +... LL | want_bar_for_any_ccx(b); | ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` - | - = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr index a93814ad4c25e..20913b4f28c8e 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26 | +LL | where F : Foo<'x> + | - help: consider further restricting type parameter `F`: `, for<'tcx> F: Foo<'tcx>` +... LL | want_foo_for_any_tcx(f); | ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F` ... @@ -8,12 +11,13 @@ LL | fn want_foo_for_any_tcx(f: &F) | -------------------- LL | where F : for<'tcx> Foo<'tcx> | ------------------- required by this bound in `want_foo_for_any_tcx` - | - = help: consider adding a `where for<'tcx> F: Foo<'tcx>` bound error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26 | +LL | where B : Bar<'x> + | - help: consider further restricting type parameter `B`: `, for<'ccx> B: Bar<'ccx>` +... LL | want_bar_for_any_ccx(b); | ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` ... @@ -21,8 +25,6 @@ LL | fn want_bar_for_any_ccx(b: &B) | -------------------- LL | where B : for<'ccx> Bar<'ccx> | ------------------- required by this bound in `want_bar_for_any_ccx` - | - = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr index e6f7088bd4635..777a553c2a58a 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.stderr @@ -1,42 +1,50 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/kindck-impl-type-params.rs:18:13 | +LL | fn f(val: T) { + | - help: consider restricting this bound: `T: std::marker::Send` +LL | let t: S = S(marker::PhantomData); LL | let a = &t as &dyn Gettable; | ^^ `T` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `T` - = help: consider adding a `where T: std::marker::Send` bound = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:18:13 | +LL | fn f(val: T) { + | - help: consider restricting this bound: `T: std::marker::Copy` +LL | let t: S = S(marker::PhantomData); LL | let a = &t as &dyn Gettable; | ^^ the trait `std::marker::Copy` is not implemented for `T` | - = help: consider adding a `where T: std::marker::Copy` bound = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` error[E0277]: `T` cannot be sent between threads safely --> $DIR/kindck-impl-type-params.rs:25:31 | +LL | fn g(val: T) { + | - help: consider restricting this bound: `T: std::marker::Send` +LL | let t: S = S(marker::PhantomData); LL | let a: &dyn Gettable = &t; | ^^ `T` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `T` - = help: consider adding a `where T: std::marker::Send` bound = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:25:31 | +LL | fn g(val: T) { + | - help: consider restricting this bound: `T: std::marker::Copy` +LL | let t: S = S(marker::PhantomData); LL | let a: &dyn Gettable = &t; | ^^ the trait `std::marker::Copy` is not implemented for `T` | - = help: consider adding a `where T: std::marker::Copy` bound = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` diff --git a/src/test/ui/phantom-oibit.stderr b/src/test/ui/phantom-oibit.stderr index ac48ee0cb0fe3..4d9d06b8986d5 100644 --- a/src/test/ui/phantom-oibit.stderr +++ b/src/test/ui/phantom-oibit.stderr @@ -3,12 +3,13 @@ error[E0277]: `T` cannot be shared between threads safely | LL | fn is_zen(_: T) {} | ------ --- required by this bound in `is_zen` -... +LL | +LL | fn not_sync(x: Guard) { + | - help: consider restricting this bound: `T: std::marker::Sync` LL | is_zen(x) | ^ `T` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `T` - = help: consider adding a `where T: std::marker::Sync` bound = note: required because of the requirements on the impl of `Zen` for `&T` = note: required because it appears within the type `std::marker::PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` @@ -19,11 +20,12 @@ error[E0277]: `T` cannot be shared between threads safely LL | fn is_zen(_: T) {} | ------ --- required by this bound in `is_zen` ... +LL | fn nested_not_sync(x: Nested>) { + | - help: consider restricting this bound: `T: std::marker::Sync` LL | is_zen(x) | ^ `T` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `T` - = help: consider adding a `where T: std::marker::Sync` bound = note: required because of the requirements on the impl of `Zen` for `&T` = note: required because it appears within the type `std::marker::PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` diff --git a/src/test/ui/suggestions/restrict-type-argument.rs b/src/test/ui/suggestions/restrict-type-argument.rs new file mode 100644 index 0000000000000..c4ebfbe922c09 --- /dev/null +++ b/src/test/ui/suggestions/restrict-type-argument.rs @@ -0,0 +1,31 @@ +fn is_send(val: T) {} + +fn use_impl_sync(val: impl Sync) { + is_send(val); //~ ERROR `impl Sync` cannot be sent between threads safely +} + +fn use_where(val: S) where S: Sync { + is_send(val); //~ ERROR `S` cannot be sent between threads safely +} + +fn use_bound(val: S) { + is_send(val); //~ ERROR `S` cannot be sent between threads safely +} + +fn use_bound_2< + S // Make sure we can synthezise a correct suggestion span for this case + : + Sync +>(val: S) { + is_send(val); //~ ERROR `S` cannot be sent between threads safely +} + +fn use_bound_and_where(val: S) where S: std::fmt::Debug { + is_send(val); //~ ERROR `S` cannot be sent between threads safely +} + +fn use_unbound(val: S) { + is_send(val); //~ ERROR `S` cannot be sent between threads safely +} + +fn main() {} diff --git a/src/test/ui/suggestions/restrict-type-argument.stderr b/src/test/ui/suggestions/restrict-type-argument.stderr new file mode 100644 index 0000000000000..d6840ca4d7265 --- /dev/null +++ b/src/test/ui/suggestions/restrict-type-argument.stderr @@ -0,0 +1,83 @@ +error[E0277]: `impl Sync` cannot be sent between threads safely + --> $DIR/restrict-type-argument.rs:4:13 + | +LL | fn is_send(val: T) {} + | ------- ---- required by this bound in `is_send` +LL | +LL | fn use_impl_sync(val: impl Sync) { + | --------- help: consider further restricting this bound: `impl Sync + std::marker::Send` +LL | is_send(val); + | ^^^ `impl Sync` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `impl Sync` + +error[E0277]: `S` cannot be sent between threads safely + --> $DIR/restrict-type-argument.rs:8:13 + | +LL | fn is_send(val: T) {} + | ------- ---- required by this bound in `is_send` +... +LL | fn use_where(val: S) where S: Sync { + | - help: consider further restricting type parameter `S`: `, S: std::marker::Send` +LL | is_send(val); + | ^^^ `S` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `S` + +error[E0277]: `S` cannot be sent between threads safely + --> $DIR/restrict-type-argument.rs:12:13 + | +LL | fn is_send(val: T) {} + | ------- ---- required by this bound in `is_send` +... +LL | fn use_bound(val: S) { + | -- help: consider further restricting this bound: `S: std::marker::Send +` +LL | is_send(val); + | ^^^ `S` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `S` + +error[E0277]: `S` cannot be sent between threads safely + --> $DIR/restrict-type-argument.rs:20:13 + | +LL | fn is_send(val: T) {} + | ------- ---- required by this bound in `is_send` +... +LL | / S // Make sure we can synthezise a correct suggestion span for this case +LL | | : + | |_____- help: consider further restricting this bound: `S: std::marker::Send +` +... +LL | is_send(val); + | ^^^ `S` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `S` + +error[E0277]: `S` cannot be sent between threads safely + --> $DIR/restrict-type-argument.rs:24:13 + | +LL | fn is_send(val: T) {} + | ------- ---- required by this bound in `is_send` +... +LL | fn use_bound_and_where(val: S) where S: std::fmt::Debug { + | - help: consider further restricting type parameter `S`: `, S: std::marker::Send` +LL | is_send(val); + | ^^^ `S` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `S` + +error[E0277]: `S` cannot be sent between threads safely + --> $DIR/restrict-type-argument.rs:28:13 + | +LL | fn is_send(val: T) {} + | ------- ---- required by this bound in `is_send` +... +LL | fn use_unbound(val: S) { + | - help: consider restricting this bound: `S: std::marker::Send` +LL | is_send(val); + | ^^^ `S` cannot be sent between threads safely + | + = help: the trait `std::marker::Send` is not implemented for `S` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/trait-suggest-where-clause.stderr b/src/test/ui/traits/trait-suggest-where-clause.stderr index d15edaa9c8146..bc9948064a30c 100644 --- a/src/test/ui/traits/trait-suggest-where-clause.stderr +++ b/src/test/ui/traits/trait-suggest-where-clause.stderr @@ -1,6 +1,9 @@ error[E0277]: the size for values of type `U` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:9:20 | +LL | fn check() { + | -- help: consider further restricting this bound: `U: std::marker::Sized +` +LL | // suggest a where-clause, if needed LL | mem::size_of::(); | ^ doesn't have a size known at compile-time | @@ -11,11 +14,13 @@ LL | pub const fn size_of() -> usize { | = help: the trait `std::marker::Sized` is not implemented for `U` = note: to learn more, visit - = help: consider adding a `where U: std::marker::Sized` bound error[E0277]: the size for values of type `U` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:12:5 | +LL | fn check() { + | -- help: consider further restricting this bound: `U: std::marker::Sized +` +... LL | mem::size_of::>(); | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | @@ -26,7 +31,6 @@ LL | pub const fn size_of() -> usize { | = help: within `Misc`, the trait `std::marker::Sized` is not implemented for `U` = note: to learn more, visit - = help: consider adding a `where U: std::marker::Sized` bound = note: required because it appears within the type `Misc` error[E0277]: the trait bound `u64: std::convert::From` is not satisfied diff --git a/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr b/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr index db77e82adbd00..85c7a55c31379 100644 --- a/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr +++ b/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr @@ -7,10 +7,10 @@ LL | c.same_as(22) error[E0277]: the trait bound `C: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:30:7 | +LL | fn with_trait(c: &C) -> bool { + | -- help: consider further restricting this bound: `C: CompareTo +` LL | c.same_as(22) | ^^^^^^^ the trait `CompareTo` is not implemented for `C` - | - = help: consider adding a `where C: CompareTo` bound error[E0277]: the trait bound `dyn CompareToInts: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:34:5 @@ -27,10 +27,10 @@ error[E0277]: the trait bound `C: CompareTo` is not satisfied LL | fn same_as(&self, t: T) -> bool; | -------------------------------- required by `CompareTo::same_as` ... +LL | fn with_ufcs2(c: &C) -> bool { + | -- help: consider further restricting this bound: `C: CompareTo +` LL | CompareTo::same_as(c, 22) | ^^^^^^^^^^^^^^^^^^ the trait `CompareTo` is not implemented for `C` - | - = help: consider adding a `where C: CompareTo` bound error[E0277]: the trait bound `i64: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:42:23 diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr index dd90dd1b06fe2..63c07224353e2 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr @@ -9,8 +9,10 @@ error[E0277]: the trait bound `T: Trait` is not satisfied | LL | type Underconstrained = impl 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` +... +LL | fn underconstrain(_: T) -> Underconstrained { + | - help: consider restricting this bound: `T: Trait` | - = help: consider adding a `where T: Trait` bound = note: the return type of a function must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 574432bdcf6de..ba892f6ed7c7b 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -15,9 +15,11 @@ error[E0277]: `U` doesn't implement `std::fmt::Debug` | LL | type Underconstrained = impl 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` +... +LL | fn underconstrained(_: U) -> Underconstrained { + | - help: consider restricting this bound: `U: std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `U` - = help: consider adding a `where U: std::fmt::Debug` bound = note: the return type of a function must have a statically known size error[E0277]: `V` doesn't implement `std::fmt::Debug` @@ -25,9 +27,11 @@ error[E0277]: `V` doesn't implement `std::fmt::Debug` | LL | type Underconstrained2 = impl 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` +... +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | - help: consider restricting this bound: `V: std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `V` - = help: consider adding a `where V: std::fmt::Debug` bound = note: the return type of a function must have a statically known size error: aborting due to 4 previous errors diff --git a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr index b3139083b1ac8..a84aef5fdbdb6 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr @@ -1,6 +1,8 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/typeck-default-trait-impl-send-param.rs:5:15 | +LL | fn foo() { + | - help: consider restricting this bound: `T: std::marker::Send` LL | is_send::() | ^ `T` cannot be sent between threads safely ... @@ -8,7 +10,6 @@ LL | fn is_send() { | ------- ---- required by this bound in `is_send` | = help: the trait `std::marker::Send` is not implemented for `T` - = help: consider adding a `where T: std::marker::Send` bound error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr index e56176690a113..bd97b0203b510 100644 --- a/src/test/ui/unsized/unsized-bare-typaram.stderr +++ b/src/test/ui/unsized/unsized-bare-typaram.stderr @@ -4,11 +4,12 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim LL | fn bar() { } | --- - required by this bound in `bar` LL | fn foo() { bar::() } - | ^ doesn't have a size known at compile-time + | -- ^ doesn't have a size known at compile-time + | | + | help: consider further restricting this bound: `T: std::marker::Sized +` | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit - = help: consider adding a `where T: std::marker::Sized` bound error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr index dff934834ef2c..341d3e4cc2df2 100644 --- a/src/test/ui/unsized/unsized-enum.stderr +++ b/src/test/ui/unsized/unsized-enum.stderr @@ -5,11 +5,12 @@ LL | enum Foo { FooSome(U), FooNone } | ----------- required by `Foo` LL | fn foo1() { not_sized::>() } // Hunky dory. LL | fn foo2() { not_sized::>() } - | ^^^^^^ doesn't have a size known at compile-time + | -- ^^^^^^ doesn't have a size known at compile-time + | | + | help: consider further restricting this bound: `T: std::marker::Sized +` | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit - = help: consider adding a `where T: std::marker::Sized` bound error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr index 0d4776ff6c25b..2894d5d56710d 100644 --- a/src/test/ui/unsized/unsized-struct.stderr +++ b/src/test/ui/unsized/unsized-struct.stderr @@ -5,11 +5,12 @@ LL | struct Foo { data: T } | ------------- required by `Foo` LL | fn foo1() { not_sized::>() } // Hunky dory. LL | fn foo2() { not_sized::>() } - | ^^^^^^ doesn't have a size known at compile-time + | -- ^^^^^^ doesn't have a size known at compile-time + | | + | help: consider further restricting this bound: `T: std::marker::Sized +` | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit - = help: consider adding a `where T: std::marker::Sized` bound error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unsized-struct.rs:13:24 @@ -18,11 +19,12 @@ LL | fn is_sized() { } | -------- - required by this bound in `is_sized` ... LL | fn bar2() { is_sized::>() } - | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | -- ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | | + | help: consider further restricting this bound: `T: std::marker::Sized +` | = help: within `Bar`, the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit - = help: consider adding a `where T: std::marker::Sized` bound = note: required because it appears within the type `Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr index c821a08f6b585..232296ad09126 100644 --- a/src/test/ui/unsized3.stderr +++ b/src/test/ui/unsized3.stderr @@ -1,6 +1,8 @@ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:7:13 | +LL | fn f1(x: &X) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | f2::(x); | ^ doesn't have a size known at compile-time ... @@ -9,11 +11,12 @@ LL | fn f2(x: &X) { | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:18:13 | +LL | fn f3(x: &X) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | f4::(x); | ^ doesn't have a size known at compile-time ... @@ -22,7 +25,6 @@ LL | fn f4(x: &X) { | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:33:8 @@ -30,35 +32,38 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim LL | fn f5(x: &Y) {} | -- - required by this bound in `f5` ... +LL | fn f8(x1: &S, x2: &S) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | f5(x1); | ^^ doesn't have a size known at compile-time | = help: within `S`, the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: required because it appears within the type `S` error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:40:8 | +LL | fn f9(x1: Box>) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | f5(&(*x1, 34)); | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `S`, the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: required because it appears within the type `S` = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:45:9 | +LL | fn f10(x1: Box>) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | f5(&(32, *x1)); | ^^^^^^^^^ doesn't have a size known at compile-time | = help: within `({integer}, S)`, the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: required because it appears within the type `S` = note: required because it appears within the type `({integer}, S)` = note: tuples must have a statically known size to be initialized @@ -69,12 +74,13 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim LL | fn f5(x: &Y) {} | -- - required by this bound in `f5` ... +LL | fn f10(x1: Box>) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | f5(&(32, *x1)); | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `({integer}, S)`, the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: required because it appears within the type `S` = note: required because it appears within the type `({integer}, S)` diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr index a6a26573e7c59..95acd987a5a27 100644 --- a/src/test/ui/unsized6.stderr +++ b/src/test/ui/unsized6.stderr @@ -1,129 +1,148 @@ error[E0277]: the size for values of type `Y` cannot be known at compilation time --> $DIR/unsized6.rs:9:9 | +LL | fn f1(x: &X) { + | -- help: consider further restricting this bound: `Y: std::marker::Sized +` +... LL | let y: Y; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Y` = note: to learn more, visit - = help: consider adding a `where Y: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:7:12 | +LL | fn f1(x: &X) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` +LL | let _: W; // <-- this is OK, no bindings created, no initializer. LL | let _: (isize, (X, isize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `Z` cannot be known at compilation time --> $DIR/unsized6.rs:11:12 | +LL | fn f1(x: &X) { + | -- help: consider further restricting this bound: `Z: std::marker::Sized +` +... LL | let y: (isize, (Z, usize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Z` = note: to learn more, visit - = help: consider adding a `where Z: std::marker::Sized` bound = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:15:9 | +LL | fn f2(x: &X) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | let y: X; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `Y` cannot be known at compilation time --> $DIR/unsized6.rs:17:12 | +LL | fn f2(x: &X) { + | -- help: consider further restricting this bound: `Y: std::marker::Sized +` +... LL | let y: (isize, (Y, isize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Y` = note: to learn more, visit - = help: consider adding a `where Y: std::marker::Sized` bound = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:22:9 | +LL | fn f3(x1: Box, x2: Box, x3: Box) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | let y: X = *x1; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:24:9 | +LL | fn f3(x1: Box, x2: Box, x3: Box) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` +... LL | let y = *x2; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:26:10 | +LL | fn f3(x1: Box, x2: Box, x3: Box) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` +... LL | let (y, z) = (*x3, 4); | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:30:9 | +LL | fn f4(x1: Box, x2: Box, x3: Box) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | let y: X = *x1; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:32:9 | +LL | fn f4(x1: Box, x2: Box, x3: Box) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` +... LL | let y = *x2; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:34:10 | +LL | fn f4(x1: Box, x2: Box, x3: Box) { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` +... LL | let (y, z) = (*x3, 4); | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -131,11 +150,12 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:38:18 | LL | fn g1(x: X) {} - | ^ doesn't have a size known at compile-time + | -- ^ doesn't have a size known at compile-time + | | + | help: consider further restricting this bound: `X: std::marker::Sized +` | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -143,11 +163,12 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:40:22 | LL | fn g2(x: X) {} - | ^ doesn't have a size known at compile-time + | -- ^ doesn't have a size known at compile-time + | | + | help: consider further restricting this bound: `X: std::marker::Sized +` | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/wf/wf-impl-associated-type-trait.stderr b/src/test/ui/wf/wf-impl-associated-type-trait.stderr index ceafb4f61578b..6d71670e6a84c 100644 --- a/src/test/ui/wf/wf-impl-associated-type-trait.stderr +++ b/src/test/ui/wf/wf-impl-associated-type-trait.stderr @@ -4,10 +4,10 @@ error[E0277]: the trait bound `T: MyHash` is not satisfied LL | pub struct MySet { | -------------------------- required by `MySet` ... +LL | impl Foo for T { + | - help: consider restricting this bound: `T: MyHash` LL | type Bar = MySet; | ^^^^^^^^^^^^^^^^^^^^ the trait `MyHash` is not implemented for `T` - | - = help: consider adding a `where T: MyHash` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr index 1e258864d0367..21f825ac9ef9a 100644 --- a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr +++ b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr @@ -4,11 +4,11 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied LL | trait ExtraCopy { } | ----------------------- required by `ExtraCopy` ... +LL | impl Foo { + | - help: consider restricting this bound: `U: std::marker::Copy` LL | / fn foo(self) where T: ExtraCopy LL | | {} | |______^ the trait `std::marker::Copy` is not implemented for `U` - | - = help: consider adding a `where U: std::marker::Copy` bound error: aborting due to previous error From 5b7ffd93330142d433ed3035ef838638dc6afa3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 8 Oct 2019 11:03:35 -0700 Subject: [PATCH 02/16] Handle more cases --- src/librustc/traits/error_reporting.rs | 11 ++++++++++- .../builtin-superkinds-double-superkind.stderr | 10 ++++++---- .../builtin-superkinds-in-metadata.stderr | 5 +++-- .../builtin-superkinds-typaram-not-send.stderr | 5 +++-- ...ounds-cant-promote-superkind-in-struct.stderr | 6 ++++-- src/test/ui/issues/issue-21837.stderr | 6 +++--- src/test/ui/issues/issue-27060-2.stderr | 3 ++- .../ui/issues/issue-43784-associated-type.stderr | 6 +++--- src/test/ui/issues/issue-43784-supertrait.stderr | 6 +++--- .../defaultimpl/specialization-wfcheck.stderr | 6 +++--- .../trait-bounds-on-structs-and-enums.stderr | 14 +++++++------- src/test/ui/type/type-check-defaults.stderr | 7 ++++--- src/test/ui/union/union-sized-field.stderr | 9 ++++++--- src/test/ui/unsized/unsized-enum2.stderr | 16 ++++++++++++---- .../unsized-inherent-impl-self-type.stderr | 5 +++-- .../unsized/unsized-trait-impl-self-type.stderr | 5 +++-- .../unsized/unsized-trait-impl-trait-arg.stderr | 5 +++-- src/test/ui/unsized5.stderr | 13 +++++++++---- src/test/ui/unsized7.stderr | 5 +++-- src/test/ui/wf/wf-enum-bound.stderr | 3 +-- .../ui/wf/wf-enum-fields-struct-variant.stderr | 5 +++-- src/test/ui/wf/wf-enum-fields.stderr | 4 ++-- src/test/ui/wf/wf-fn-where-clause.stderr | 7 ++++--- src/test/ui/wf/wf-in-fn-arg.stderr | 7 ++++--- src/test/ui/wf/wf-in-fn-ret.stderr | 7 ++++--- src/test/ui/wf/wf-in-fn-type-arg.stderr | 5 +++-- src/test/ui/wf/wf-in-fn-type-ret.stderr | 5 +++-- src/test/ui/wf/wf-in-fn-where-clause.stderr | 3 +-- src/test/ui/wf/wf-in-obj-type-trait.stderr | 5 +++-- .../ui/wf/wf-inherent-impl-where-clause.stderr | 7 ++++--- src/test/ui/wf/wf-struct-bound.stderr | 3 +-- src/test/ui/wf/wf-struct-field.stderr | 4 ++-- .../ui/wf/wf-trait-associated-type-bound.stderr | 7 ++++--- src/test/ui/wf/wf-trait-bound.stderr | 3 +-- src/test/ui/wf/wf-trait-superbound.stderr | 7 ++++--- 35 files changed, 134 insertions(+), 91 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b7c7fd4729f0a..a717fb7f7c0f8 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -969,7 +969,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_ref: &ty::PolyTraitRef<'_>, body_id: hir::HirId, ) { - let node = self.tcx.hir().find(self.tcx.hir().get_parent_item(body_id)); + let node = self.tcx.hir() + .find(self.tcx.hir().get_parent_item(body_id)) + .or_else(|| self.tcx.hir().find(body_id)); + debug!( + "suggest_restricting_param_bound node={:?} - trait_ref={:?} ty={:?} ({:?})", + node, + trait_ref, + trait_ref.self_ty(), + trait_ref.self_ty().kind, + ); if let ty::Param(param_ty) = &trait_ref.self_ty().kind { let restrict_msg = "consider further restricting this bound"; let param_name = param_ty.name.as_str(); diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr index 9771436d167df..5be6ab05d6607 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr @@ -2,20 +2,22 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/builtin-superkinds-double-superkind.rs:6:24 | LL | impl Foo for (T,) { } - | ^^^ `T` cannot be sent between threads safely + | -- ^^^ `T` cannot be sent between threads safely + | | + | help: consider further restricting this bound: `T: std::marker::Send +` | = help: within `(T,)`, the trait `std::marker::Send` is not implemented for `T` - = help: consider adding a `where T: std::marker::Send` bound = note: required because it appears within the type `(T,)` error[E0277]: `T` cannot be shared between threads safely --> $DIR/builtin-superkinds-double-superkind.rs:9:16 | LL | impl Foo for (T,T) { } - | ^^^ `T` cannot be shared between threads safely + | -- ^^^ `T` cannot be shared between threads safely + | | + | help: consider further restricting this bound: `T: std::marker::Sync +` | = help: within `(T, T)`, the trait `std::marker::Sync` is not implemented for `T` - = help: consider adding a `where T: std::marker::Sync` bound = note: required because it appears within the type `(T, T)` error: aborting due to 2 previous errors diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr index 61c18a24fb0c9..8cce9bfdf52a8 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr @@ -2,10 +2,11 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/builtin-superkinds-in-metadata.rs:13:23 | LL | impl RequiresRequiresShareAndSend for X { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `T` cannot be sent between threads safely + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `T` cannot be sent between threads safely + | | + | help: consider further restricting this bound: `T: std::marker::Send +` | = help: within `X`, the trait `std::marker::Send` is not implemented for `T` - = help: consider adding a `where T: std::marker::Send` bound = note: required because it appears within the type `X` error: aborting due to previous error diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr index dc5479e5e2da6..4381a5b868262 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr @@ -2,10 +2,11 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/builtin-superkinds-typaram-not-send.rs:5:24 | LL | impl Foo for T { } - | ^^^ `T` cannot be sent between threads safely + | -- ^^^ `T` cannot be sent between threads safely + | | + | help: consider further restricting this bound: `T: std::marker::Send +` | = help: the trait `std::marker::Send` is not implemented for `T` - = help: consider adding a `where T: std::marker::Send` bound error: aborting due to previous error diff --git a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr index 51077b1b2922e..3c8f637e13369 100644 --- a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr +++ b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr @@ -4,14 +4,16 @@ error[E0277]: `F` cannot be sent between threads safely LL | struct X where F: FnOnce() + 'static + Send { | ---------------------------------------------- required by `X` ... -LL | / fn foo(blk: F) -> X where F: FnOnce() + 'static { +LL | fn foo(blk: F) -> X where F: FnOnce() + 'static { + | ^ - help: consider further restricting type parameter `F`: `, F: std::marker::Send` + | _| + | | LL | | LL | | return X { field: blk }; LL | | } | |_^ `F` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `F` - = help: consider adding a `where F: std::marker::Send` bound error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21837.stderr b/src/test/ui/issues/issue-21837.stderr index 20d02a90315d0..50fdf2d6185be 100644 --- a/src/test/ui/issues/issue-21837.stderr +++ b/src/test/ui/issues/issue-21837.stderr @@ -5,9 +5,9 @@ LL | pub struct Foo(T); | ---------------------------- required by `Foo` ... LL | impl Trait2 for Foo {} - | ^^^^^^ the trait `Bound` is not implemented for `T` - | - = help: consider adding a `where T: Bound` bound + | - ^^^^^^ the trait `Bound` is not implemented for `T` + | | + | help: consider restricting this bound: `T: Bound` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-27060-2.stderr b/src/test/ui/issues/issue-27060-2.stderr index f7227c3410146..553041c5106c5 100644 --- a/src/test/ui/issues/issue-27060-2.stderr +++ b/src/test/ui/issues/issue-27060-2.stderr @@ -1,12 +1,13 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/issue-27060-2.rs:3:5 | +LL | pub struct Bad { + | -- help: consider further restricting this bound: `T: std::marker::Sized +` LL | data: T, | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit - = help: consider adding a `where T: std::marker::Sized` bound = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43784-associated-type.stderr b/src/test/ui/issues/issue-43784-associated-type.stderr index fc05d280693b8..e91e53499ce6c 100644 --- a/src/test/ui/issues/issue-43784-associated-type.stderr +++ b/src/test/ui/issues/issue-43784-associated-type.stderr @@ -2,9 +2,9 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/issue-43784-associated-type.rs:13:9 | LL | impl Complete for T { - | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound + | - ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | | + | help: consider restricting this bound: `T: std::marker::Copy` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43784-supertrait.stderr b/src/test/ui/issues/issue-43784-supertrait.stderr index 4c423f2e77fe8..5ac32041bce48 100644 --- a/src/test/ui/issues/issue-43784-supertrait.stderr +++ b/src/test/ui/issues/issue-43784-supertrait.stderr @@ -2,9 +2,9 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/issue-43784-supertrait.rs:8:9 | LL | impl Complete for T {} - | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound + | - ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | | + | help: consider restricting this bound: `T: std::marker::Copy` error: aborting due to previous error diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr index 45951561e7264..5275b7b1ddfa5 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr @@ -2,9 +2,9 @@ error[E0277]: the trait bound `U: std::cmp::Eq` is not satisfied --> $DIR/specialization-wfcheck.rs:7:17 | LL | default impl Foo<'static, U> for () {} - | ^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `U` - | - = help: consider adding a `where U: std::cmp::Eq` bound + | - ^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `U` + | | + | help: consider restricting this bound: `U: std::cmp::Eq` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr index bd76df8071a53..96bbd1f3e4f17 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr @@ -5,9 +5,9 @@ LL | struct Foo { | ------------------- required by `Foo` ... LL | impl Foo { - | ^^^^^^ the trait `Trait` is not implemented for `T` - | - = help: consider adding a `where T: Trait` bound + | - ^^^^^^ the trait `Trait` is not implemented for `T` + | | + | help: consider restricting this bound: `T: Trait` error[E0277]: the trait bound `isize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:19:5 @@ -33,10 +33,10 @@ error[E0277]: the trait bound `U: Trait` is not satisfied LL | struct Foo { | ------------------- required by `Foo` ... +LL | struct Badness { + | - help: consider restricting this bound: `U: Trait` LL | b: Foo, | ^^^^^^^^^ the trait `Trait` is not implemented for `U` - | - = help: consider adding a `where U: Trait` bound error[E0277]: the trait bound `V: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:31:21 @@ -44,10 +44,10 @@ error[E0277]: the trait bound `V: Trait` is not satisfied LL | enum Bar { | ----------------- required by `Bar` ... +LL | enum MoreBadness { + | - help: consider restricting this bound: `V: Trait` LL | EvenMoreBadness(Bar), | ^^^^^^ the trait `Trait` is not implemented for `V` - | - = help: consider adding a `where V: Trait` bound error[E0277]: the trait bound `i32: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:35:5 diff --git a/src/test/ui/type/type-check-defaults.stderr b/src/test/ui/type/type-check-defaults.stderr index 742a709958fa0..6802bc38b89c9 100644 --- a/src/test/ui/type/type-check-defaults.stderr +++ b/src/test/ui/type/type-check-defaults.stderr @@ -52,9 +52,10 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | trait Super { } | -------------------- required by `Super` LL | trait Base: Super { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound + | ^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | help: consider restricting this bound: `T: std::marker::Copy` + | the trait `std::marker::Copy` is not implemented for `T` error[E0277]: cannot add `u8` to `i32` --> $DIR/type-check-defaults.rs:24:66 diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index 8914003068385..c9fec1d21d152 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -1,34 +1,37 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:4:5 | +LL | union Foo { + | -- help: consider further restricting this bound: `T: std::marker::Sized +` LL | value: T, | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit - = help: consider adding a `where T: std::marker::Sized` bound = note: no field of a union may have a dynamically sized type error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:9:5 | +LL | struct Foo2 { + | -- help: consider further restricting this bound: `T: std::marker::Sized +` LL | value: T, | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit - = help: consider adding a `where T: std::marker::Sized` bound = note: only the last field of a struct may have a dynamically sized type error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:15:11 | +LL | enum Foo3 { + | -- help: consider further restricting this bound: `T: std::marker::Sized +` LL | Value(T), | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit - = help: consider adding a `where T: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type error: aborting due to 3 previous errors diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr index cdd5747d86b0f..e85b6d662f9d5 100644 --- a/src/test/ui/unsized/unsized-enum2.stderr +++ b/src/test/ui/unsized/unsized-enum2.stderr @@ -1,45 +1,53 @@ error[E0277]: the size for values of type `W` cannot be known at compilation time --> $DIR/unsized-enum2.rs:23:8 | +LL | enum E { + | -- help: consider further restricting this bound: `W: std::marker::Sized +` +LL | // parameter LL | VA(W), | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `W` = note: to learn more, visit - = help: consider adding a `where W: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized-enum2.rs:25:8 | +LL | enum E { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` +... LL | VB{x: X}, | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `Y` cannot be known at compilation time --> $DIR/unsized-enum2.rs:27:15 | +LL | enum E { + | -- help: consider further restricting this bound: `Y: std::marker::Sized +` +... LL | VC(isize, Y), | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Y` = note: to learn more, visit - = help: consider adding a `where Y: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `Z` cannot be known at compilation time --> $DIR/unsized-enum2.rs:29:18 | +LL | enum E { + | -- help: consider further restricting this bound: `Z: std::marker::Sized +` +... LL | VD{u: isize, x: Z}, | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Z` = note: to learn more, visit - = help: consider adding a `where Z: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `[u8]` cannot be known at compilation time diff --git a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr index 1a726bb089f6e..280b8fd43cab0 100644 --- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr @@ -5,11 +5,12 @@ LL | struct S5(Y); | ---------------- required by `S5` LL | LL | impl S5 { - | ^^^^^ doesn't have a size known at compile-time + | -- ^^^^^ doesn't have a size known at compile-time + | | + | help: consider further restricting this bound: `X: std::marker::Sized +` | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr index f399f8ded1085..ba1550439c0d9 100644 --- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr @@ -5,11 +5,12 @@ LL | struct S5(Y); | ---------------- required by `S5` LL | LL | impl T3 for S5 { - | ^^^^^ doesn't have a size known at compile-time + | -- ^^^^^ doesn't have a size known at compile-time + | | + | help: consider further restricting this bound: `X: std::marker::Sized +` | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr index ee0d5ccccfe11..41371d63f9e53 100644 --- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr @@ -2,11 +2,12 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized-trait-impl-trait-arg.rs:8:17 | LL | impl T2 for S4 { - | ^^^^^ doesn't have a size known at compile-time + | -- ^^^^^ doesn't have a size known at compile-time + | | + | help: consider further restricting this bound: `X: std::marker::Sized +` | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound error: aborting due to previous error diff --git a/src/test/ui/unsized5.stderr b/src/test/ui/unsized5.stderr index 6dce9a046066f..bfd3f4aa691eb 100644 --- a/src/test/ui/unsized5.stderr +++ b/src/test/ui/unsized5.stderr @@ -1,23 +1,26 @@ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized5.rs:4:5 | +LL | struct S1 { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | f1: X, | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: only the last field of a struct may have a dynamically sized type error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized5.rs:10:5 | +LL | struct S2 { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` +LL | f: isize, LL | g: X, | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: only the last field of a struct may have a dynamically sized type error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -43,23 +46,25 @@ LL | f: [u8], error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized5.rs:25:8 | +LL | enum E { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | V1(X, isize), | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized5.rs:29:8 | +LL | enum F { + | -- help: consider further restricting this bound: `X: std::marker::Sized +` LL | V2{f1: X, f: isize}, | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type error: aborting due to 6 previous errors diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr index bb83b1811844a..c77503a6f87aa 100644 --- a/src/test/ui/unsized7.stderr +++ b/src/test/ui/unsized7.stderr @@ -2,11 +2,12 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized7.rs:12:21 | LL | impl T1 for S3 { - | ^^^^^ doesn't have a size known at compile-time + | -- ^^^^^ doesn't have a size known at compile-time + | | + | help: consider further restricting this bound: `X: std::marker::Sized +` | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit - = help: consider adding a `where X: std::marker::Sized` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-bound.stderr b/src/test/ui/wf/wf-enum-bound.stderr index d5632f4a9c24e..eaacd6b6881ef 100644 --- a/src/test/ui/wf/wf-enum-bound.stderr +++ b/src/test/ui/wf/wf-enum-bound.stderr @@ -6,12 +6,11 @@ LL | trait ExtraCopy { } LL | LL | / enum SomeEnum LL | | where T: ExtraCopy + | | - help: consider further restricting type parameter `U`: `, U: std::marker::Copy` LL | | { LL | | SomeVariant(T,U) LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` - | - = help: consider adding a `where U: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr index 51ee23fc5aa6d..52882c460d228 100644 --- a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr +++ b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr @@ -4,10 +4,11 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied LL | struct IsCopy { | --------------------- required by `IsCopy` ... +LL | enum AnotherEnum { + | - help: consider restricting this bound: `A: std::marker::Copy` +LL | AnotherVariant { LL | f: IsCopy | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` - | - = help: consider adding a `where A: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-fields.stderr b/src/test/ui/wf/wf-enum-fields.stderr index 5f4e7c66f54ca..0fea35d68ea6f 100644 --- a/src/test/ui/wf/wf-enum-fields.stderr +++ b/src/test/ui/wf/wf-enum-fields.stderr @@ -4,10 +4,10 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied LL | struct IsCopy { | --------------------- required by `IsCopy` ... +LL | enum SomeEnum { + | - help: consider restricting this bound: `A: std::marker::Copy` LL | SomeVariant(IsCopy) | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` - | - = help: consider adding a `where A: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr index 4bc2e370f29fa..9b8b04a7b86a3 100644 --- a/src/test/ui/wf/wf-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-fn-where-clause.stderr @@ -4,12 +4,13 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied LL | trait ExtraCopy { } | ----------------------- required by `ExtraCopy` LL | -LL | / fn foo() where T: ExtraCopy +LL | fn foo() where T: ExtraCopy + | ^ - help: consider further restricting type parameter `U`: `, U: std::marker::Copy` + | _| + | | LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` - | - = help: consider adding a `where U: std::marker::Copy` bound error[E0277]: the size for values of type `(dyn std::marker::Copy + 'static)` cannot be known at compilation time --> $DIR/wf-fn-where-clause.rs:12:1 diff --git a/src/test/ui/wf/wf-in-fn-arg.stderr b/src/test/ui/wf/wf-in-fn-arg.stderr index e7432f8198734..3798ba1ec6e75 100644 --- a/src/test/ui/wf/wf-in-fn-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-arg.stderr @@ -4,12 +4,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | struct MustBeCopy { | ------------------------- required by `MustBeCopy` ... -LL | / fn bar(_: &MustBeCopy) +LL | fn bar(_: &MustBeCopy) + | ^ - help: consider restricting this bound: `T: std::marker::Copy` + | _| + | | LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-ret.stderr b/src/test/ui/wf/wf-in-fn-ret.stderr index 005ffe84502de..2e46ce4900033 100644 --- a/src/test/ui/wf/wf-in-fn-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-ret.stderr @@ -4,12 +4,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | struct MustBeCopy { | ------------------------- required by `MustBeCopy` ... -LL | / fn bar() -> MustBeCopy +LL | fn bar() -> MustBeCopy + | ^ - help: consider restricting this bound: `T: std::marker::Copy` + | _| + | | LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-type-arg.stderr b/src/test/ui/wf/wf-in-fn-type-arg.stderr index b4cd921040225..db4fb9f97f52d 100644 --- a/src/test/ui/wf/wf-in-fn-type-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-type-arg.stderr @@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | struct MustBeCopy { | ------------------------- required by `MustBeCopy` ... +LL | struct Bar { + | - help: consider restricting this bound: `T: std::marker::Copy` +LL | // needs T: Copy LL | x: fn(MustBeCopy) | ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-type-ret.stderr b/src/test/ui/wf/wf-in-fn-type-ret.stderr index 988fbed8e9107..09f8aa2a20182 100644 --- a/src/test/ui/wf/wf-in-fn-type-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-type-ret.stderr @@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | struct MustBeCopy { | ------------------------- required by `MustBeCopy` ... +LL | struct Foo { + | - help: consider restricting this bound: `T: std::marker::Copy` +LL | // needs T: 'static LL | x: fn() -> MustBeCopy | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-where-clause.stderr b/src/test/ui/wf/wf-in-fn-where-clause.stderr index 0af38ddcffea3..979802dec4998 100644 --- a/src/test/ui/wf/wf-in-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-in-fn-where-clause.stderr @@ -6,11 +6,10 @@ LL | trait MustBeCopy { ... LL | / fn bar() LL | | where T: MustBeCopy + | | - help: consider further restricting type parameter `U`: `, U: std::marker::Copy` LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` - | - = help: consider adding a `where U: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-obj-type-trait.stderr b/src/test/ui/wf/wf-in-obj-type-trait.stderr index 0f4b4e417ca4f..2711820d82c65 100644 --- a/src/test/ui/wf/wf-in-obj-type-trait.stderr +++ b/src/test/ui/wf/wf-in-obj-type-trait.stderr @@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | struct MustBeCopy { | ------------------------- required by `MustBeCopy` ... +LL | struct Bar { + | - help: consider restricting this bound: `T: std::marker::Copy` +LL | // needs T: Copy LL | x: dyn Object> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr index 4c389b3ef3ef2..35b9093381329 100644 --- a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr +++ b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr @@ -4,12 +4,13 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied LL | trait ExtraCopy { } | ----------------------- required by `ExtraCopy` ... -LL | / impl Foo where T: ExtraCopy +LL | impl Foo where T: ExtraCopy + | ^ - help: consider further restricting type parameter `U`: `, U: std::marker::Copy` + | _| + | | LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` - | - = help: consider adding a `where U: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-struct-bound.stderr b/src/test/ui/wf/wf-struct-bound.stderr index 2028a0baa17fb..2155977349256 100644 --- a/src/test/ui/wf/wf-struct-bound.stderr +++ b/src/test/ui/wf/wf-struct-bound.stderr @@ -6,12 +6,11 @@ LL | trait ExtraCopy { } LL | LL | / struct SomeStruct LL | | where T: ExtraCopy + | | - help: consider further restricting type parameter `U`: `, U: std::marker::Copy` LL | | { LL | | data: (T,U) LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` - | - = help: consider adding a `where U: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-struct-field.stderr b/src/test/ui/wf/wf-struct-field.stderr index d2bff253678ee..6ac4f1e2da8d2 100644 --- a/src/test/ui/wf/wf-struct-field.stderr +++ b/src/test/ui/wf/wf-struct-field.stderr @@ -4,10 +4,10 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied LL | struct IsCopy { | --------------------- required by `IsCopy` ... +LL | struct SomeStruct { + | - help: consider restricting this bound: `A: std::marker::Copy` LL | data: IsCopy | ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` - | - = help: consider adding a `where A: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-associated-type-bound.stderr b/src/test/ui/wf/wf-trait-associated-type-bound.stderr index d5b2b5762a43a..af0433fd22f6e 100644 --- a/src/test/ui/wf/wf-trait-associated-type-bound.stderr +++ b/src/test/ui/wf/wf-trait-associated-type-bound.stderr @@ -4,12 +4,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | trait ExtraCopy { } | ----------------------- required by `ExtraCopy` LL | -LL | / trait SomeTrait { +LL | trait SomeTrait { + | ^ - help: consider restricting this bound: `T: std::marker::Copy` + | _| + | | LL | | type Type1: ExtraCopy; LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-bound.stderr b/src/test/ui/wf/wf-trait-bound.stderr index 85f12b2de5489..13e2f8f590149 100644 --- a/src/test/ui/wf/wf-trait-bound.stderr +++ b/src/test/ui/wf/wf-trait-bound.stderr @@ -6,11 +6,10 @@ LL | trait ExtraCopy { } LL | LL | / trait SomeTrait LL | | where T: ExtraCopy + | | - help: consider further restricting type parameter `U`: `, U: std::marker::Copy` LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` - | - = help: consider adding a `where U: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-superbound.stderr b/src/test/ui/wf/wf-trait-superbound.stderr index 377ca640536cf..a61b8dd3a3849 100644 --- a/src/test/ui/wf/wf-trait-superbound.stderr +++ b/src/test/ui/wf/wf-trait-superbound.stderr @@ -4,11 +4,12 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | trait ExtraCopy { } | ----------------------- required by `ExtraCopy` LL | -LL | / trait SomeTrait: ExtraCopy { +LL | trait SomeTrait: ExtraCopy { + | ^ - help: consider restricting this bound: `T: std::marker::Copy` + | _| + | | LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound error: aborting due to previous error From dbd75c8c40a06ac682251b67a548a8252c5d4b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 8 Oct 2019 15:22:27 -0700 Subject: [PATCH 03/16] Handle more cases involving `impl` and `trait` --- src/librustc/traits/error_reporting.rs | 147 ++++++++++-------- .../associated-types-no-suitable-bound.stderr | 7 +- .../ui/consts/too_generic_eval_ice.stderr | 8 +- src/test/ui/impl-trait/issue-55872-1.stderr | 7 +- ...traints-are-local-for-inherent-impl.stderr | 5 +- ...onstraints-are-local-for-trait-impl.stderr | 5 +- 6 files changed, 101 insertions(+), 78 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index a717fb7f7c0f8..c8baafef50a7c 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -969,90 +969,103 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_ref: &ty::PolyTraitRef<'_>, body_id: hir::HirId, ) { - let node = self.tcx.hir() - .find(self.tcx.hir().get_parent_item(body_id)) - .or_else(|| self.tcx.hir().find(body_id)); debug!( - "suggest_restricting_param_bound node={:?} - trait_ref={:?} ty={:?} ({:?})", - node, + "suggest_restricting_param_bound trait_ref={:?} ty={:?} ({:?})", trait_ref, trait_ref.self_ty(), trait_ref.self_ty().kind, ); - if let ty::Param(param_ty) = &trait_ref.self_ty().kind { - let restrict_msg = "consider further restricting this bound"; - let param_name = param_ty.name.as_str(); - - if let Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Struct(_, generics), span, .. - })) | - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Enum(_, generics), span, .. - })) | - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Union(_, generics), span, .. - })) | - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, generics, ..), span, .. - })) | - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(_, _, _, generics, ..), span, .. - })) | - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(_, _, generics, _), span, .. - })) = &node { - for param in &generics.params { - if param_name == param.name.ident().as_str() { - if param_name.starts_with("impl ") { - err.span_suggestion( - param.span, - restrict_msg, - // `impl CurrentTrait + MissingTrait` - format!("{} + {}", param.name.ident(), trait_ref), - Applicability::MachineApplicable, - ); - } else { - if generics.where_clause.predicates.is_empty() && - param.bounds.is_empty() - { + let param_ty = if let ty::Param(param_ty) = &trait_ref.self_ty().kind { + param_ty + } else { + err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); + return; + }; + + let mut hir_id = body_id; + while let Some(node) = self.tcx.hir().find(hir_id) { + debug!("suggest_restricting_param_bound node={:?}", node); + match node { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(_, generics), span, .. }) | + hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics), span, .. }) | + hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(_, generics), span, .. }) | + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Trait(_, _, generics, ..), span, .. + }) | + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(_, _, _, generics, ..), span, .. + }) | + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(_, _, generics, _), span, .. + }) | + hir::Node::Item(hir::Item { + kind: hir::ItemKind::TyAlias(_, generics), span, .. + }) | + hir::Node::Item(hir::Item { + kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), span, .. + }) | + hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) | + hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) => { + let restrict_msg = "consider further restricting this bound"; + let param_name = param_ty.name.as_str(); + for param in &generics.params { + if param_name == param.name.ident().as_str() { + if param_name.starts_with("impl ") { err.span_suggestion( param.span, - "consider restricting this bound", - format!("{}", trait_ref.to_predicate()), - Applicability::MachineApplicable, - ); - } else if !generics.where_clause.predicates.is_empty() { - err.span_suggestion( - generics.where_clause.span().unwrap().shrink_to_hi(), - &format!( - "consider further restricting type parameter `{}`", - param_ty, - ), - format!(", {}", trait_ref.to_predicate()), + restrict_msg, + // `impl CurrentTrait + MissingTrait` + format!("{} + {}", param.name.ident(), trait_ref), Applicability::MachineApplicable, ); } else { - let sp = param.span.with_hi(span.hi()); - let span = self.tcx.sess.source_map().span_through_char(sp, ':'); - if sp != param.span && sp != span { - // Only suggest if we have high certainty that the span covers - // the colon in `foo`. - err.span_suggestion(span, restrict_msg, format!( - "{} + ", - trait_ref.to_predicate(), - ), Applicability::MachineApplicable); + if generics.where_clause.predicates.is_empty() && + param.bounds.is_empty() + { + err.span_suggestion( + param.span, + "consider restricting this bound", + format!("{}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } else if !generics.where_clause.predicates.is_empty() { + err.span_suggestion( + generics.where_clause.span().unwrap().shrink_to_hi(), + &format!( + "consider further restricting type parameter `{}`", + param_ty, + ), + format!(", {}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); } else { - err.span_label(param.span, &format!( - "consider adding a `where {}` bound", - trait_ref.to_predicate(), - )); + let sp = param.span.with_hi(span.hi()); + let span = self.tcx.sess.source_map() + .span_through_char(sp, ':'); + if sp != param.span && sp != span { + // Only suggest if we have high certainty that the span + // covers the colon in `foo`. + err.span_suggestion(span, restrict_msg, format!( + "{} + ", + trait_ref.to_predicate(), + ), Applicability::MachineApplicable); + } else { + err.span_label(param.span, &format!( + "consider adding a `where {}` bound", + trait_ref.to_predicate(), + )); + } } } + return; } - return; } } + hir::Node::Crate => return, + _ => {} } + + hir_id = self.tcx.hir().get_parent_item(hir_id); } // FIXME: Add special check for `?Sized` so we don't suggest `T: Sized + ?Sized`. diff --git a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr index ada9cacbee523..78198322913c7 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr @@ -2,9 +2,10 @@ error[E0277]: the trait bound `T: Get` is not satisfied --> $DIR/associated-types-no-suitable-bound.rs:11:5 | LL | fn uhoh(foo: ::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T` - | - = help: consider adding a `where T: Get` bound + | ^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | help: consider restricting this bound: `T: Get` + | the trait `Get` is not implemented for `T` error: aborting due to previous error diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index 0733a51233e33..2fb9977f4d700 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -16,26 +16,30 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim | LL | pub struct Foo(A, B); | --------------------------- required by `Foo` +LL | +LL | impl Foo { + | - help: consider restricting this bound: `A: std::marker::Sized` ... LL | [5; Self::HOST_SIZE] == [6; 0] | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit - = help: consider adding a `where A: std::marker::Sized` bound error[E0277]: the size for values of type `B` cannot be known at compilation time --> $DIR/too_generic_eval_ice.rs:7:13 | LL | pub struct Foo(A, B); | --------------------------- required by `Foo` +LL | +LL | impl Foo { + | - help: consider restricting this bound: `B: std::marker::Sized` ... LL | [5; Self::HOST_SIZE] == [6; 0] | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `B` = note: to learn more, visit - = help: consider adding a `where B: std::marker::Sized` bound error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr index d5756c015596e..0d8ee61b5ba13 100644 --- a/src/test/ui/impl-trait/issue-55872-1.stderr +++ b/src/test/ui/impl-trait/issue-55872-1.stderr @@ -1,10 +1,11 @@ error[E0277]: the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)` --> $DIR/issue-55872-1.rs:12:5 | +LL | impl Bar for S { + | -- help: consider further restricting this bound: `S: std::marker::Copy +` LL | type E = impl Copy; | ^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `S` | - = help: consider adding a `where S: std::marker::Copy` bound = note: required because it appears within the type `(S, T)` = note: the return type of a function must have a statically known size @@ -13,8 +14,10 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied in `(S, T) | LL | type E = impl Copy; | ^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `T` +... +LL | fn foo() -> Self::E { + | -- help: consider further restricting this bound: `T: std::marker::Copy +` | - = help: consider adding a `where T: std::marker::Copy` bound = note: required because it appears within the type `(S, T)` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr index 727c9b8e06721..995b544600389 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr @@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | fn require_copy(x: T) {} | ------------ ---- required by this bound in `require_copy` ... +LL | impl Foo { + | - help: consider restricting this bound: `T: std::marker::Copy` +... LL | require_copy(self.x); | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr index 1c1937c3074db..fe575f3a28a9e 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr @@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied LL | fn require_copy(x: T) {} | ------------ ---- required by this bound in `require_copy` ... +LL | impl Foo for Bar { + | - help: consider restricting this bound: `T: std::marker::Copy` +... LL | require_copy(self.x); | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` - | - = help: consider adding a `where T: std::marker::Copy` bound error: aborting due to previous error From 99ab45b91de9fc6c07903dbe3075757f0e5e9071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 8 Oct 2019 16:03:38 -0700 Subject: [PATCH 04/16] Handle `Self` restriction needed --- src/librustc/traits/error_reporting.rs | 28 +++++++++++++++++++ .../associated-types-for-unimpl-trait.stderr | 7 +++-- ...ated-types-no-suitable-supertrait-2.stderr | 7 +++-- ...ciated-types-no-suitable-supertrait.stderr | 7 +++-- ...ted-trait-in-method-without-default.stderr | 7 +++-- src/test/ui/issues/issue-20005.stderr | 2 +- src/test/ui/issues/issue-27078.stderr | 5 ++-- .../type-params-in-different-spaces-2.stderr | 8 +++--- src/test/ui/wf/wf-trait-default-fn-arg.stderr | 7 +++-- src/test/ui/wf/wf-trait-default-fn-ret.stderr | 7 +++-- .../wf-trait-default-fn-where-clause.stderr | 7 +++-- src/test/ui/wf/wf-trait-fn-arg.stderr | 7 +++-- src/test/ui/wf/wf-trait-fn-ret.stderr | 7 +++-- .../ui/wf/wf-trait-fn-where-clause.stderr | 7 +++-- 14 files changed, 76 insertions(+), 37 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index c8baafef50a7c..6e111089d06d1 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -986,6 +986,34 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { while let Some(node) = self.tcx.hir().find(hir_id) { debug!("suggest_restricting_param_bound node={:?}", node); match node { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(decl, _, generics, _), .. + }) | + hir::Node::TraitItem(hir::TraitItem { + generics, + kind: hir::TraitItemKind::Method(hir::MethodSig { decl, .. }, _), .. + }) | + hir::Node::ImplItem(hir::ImplItem { + generics, + kind: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, _), .. + }) if param_ty.name.as_str() == "Self" => { + if !generics.where_clause.predicates.is_empty() { + err.span_suggestion( + generics.where_clause.span().unwrap().shrink_to_hi(), + "consider further restricting `Self`", + format!(", {}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion( + decl.output.span().shrink_to_hi(), + "consider further restricting `Self`", + format!(" where {}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } + return; + } hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(_, generics), span, .. }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics), span, .. }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(_, generics), span, .. }) | diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr index 9f033687a0072..79525e6362f17 100644 --- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr +++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr @@ -2,9 +2,10 @@ error[E0277]: the trait bound `Self: Get` is not satisfied --> $DIR/associated-types-for-unimpl-trait.rs:7:5 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` - | - = help: consider adding a `where Self: Get` bound + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^ + | | | + | | help: consider further restricting `Self`: `where Self: Get` + | the trait `Get` is not implemented for `Self` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr index 56cd6d09caddc..43950defc7cb9 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr @@ -2,9 +2,10 @@ error[E0277]: the trait bound `Self: Get` is not satisfied --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` - | - = help: consider adding a `where Self: Get` bound + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^ + | | | + | | help: consider further restricting `Self`: `where Self: Get` + | the trait `Get` is not implemented for `Self` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr index 71175d36f645f..82e366dbea4b4 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr @@ -2,9 +2,10 @@ error[E0277]: the trait bound `Self: Get` is not satisfied --> $DIR/associated-types-no-suitable-supertrait.rs:17:5 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` - | - = help: consider adding a `where Self: Get` bound + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^ + | | | + | | help: consider further restricting `Self`: `where Self: Get` + | the trait `Get` is not implemented for `Self` error[E0277]: the trait bound `(T, U): Get` is not satisfied --> $DIR/associated-types-no-suitable-supertrait.rs:22:5 diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr index a260e37918254..54daeca425208 100644 --- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr +++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr @@ -2,9 +2,10 @@ error[E0277]: the trait bound `Self: Get` is not satisfied --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:9:5 | LL | fn okay(&self, foo: U, bar: ::Value); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` - | - = help: consider adding a `where Self: Get` bound + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | | + | | help: consider further restricting `Self`: `where Self: Get` + | the trait `Get` is not implemented for `Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr index 2754d6bdd8306..31376f2d1be0f 100644 --- a/src/test/ui/issues/issue-20005.stderr +++ b/src/test/ui/issues/issue-20005.stderr @@ -7,13 +7,13 @@ LL | trait From { LL | / fn to( LL | | self LL | | ) -> >::Result where Dst: From { + | | - help: consider further restricting `Self`: `, Self: std::marker::Sized` LL | | From::from(self) LL | | } | |_____^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Self` = note: to learn more, visit - = help: consider adding a `where Self: std::marker::Sized` bound error: aborting due to previous error diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr index 76cc3e7b0a36e..fbc72d063f37c 100644 --- a/src/test/ui/issues/issue-27078.stderr +++ b/src/test/ui/issues/issue-27078.stderr @@ -2,11 +2,12 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation --> $DIR/issue-27078.rs:5:12 | LL | fn foo(self) -> &'static i32 { - | ^^^^ doesn't have a size known at compile-time + | ^^^^ - help: consider further restricting `Self`: `where Self: std::marker::Sized` + | | + | doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Self` = note: to learn more, visit - = help: consider adding a `where Self: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/type/type-params-in-different-spaces-2.stderr b/src/test/ui/type/type-params-in-different-spaces-2.stderr index 7d4bbc813c09c..7ce249a60b85e 100644 --- a/src/test/ui/type/type-params-in-different-spaces-2.stderr +++ b/src/test/ui/type/type-params-in-different-spaces-2.stderr @@ -4,10 +4,10 @@ error[E0277]: the trait bound `Self: Tr` is not satisfied LL | fn op(_: T) -> Self; | -------------------- required by `Tr::op` ... +LL | fn test(u: U) -> Self { + | - help: consider further restricting `Self`: `where Self: Tr` LL | Tr::op(u) | ^^^^^^ the trait `Tr` is not implemented for `Self` - | - = help: consider adding a `where Self: Tr` bound error[E0277]: the trait bound `Self: Tr` is not satisfied --> $DIR/type-params-in-different-spaces-2.rs:16:9 @@ -15,10 +15,10 @@ error[E0277]: the trait bound `Self: Tr` is not satisfied LL | fn op(_: T) -> Self; | -------------------- required by `Tr::op` ... +LL | fn test(u: U) -> Self { + | - help: consider further restricting `Self`: `where Self: Tr` LL | Tr::op(u) | ^^^^^^ the trait `Tr` is not implemented for `Self` - | - = help: consider adding a `where Self: Tr` bound error: aborting due to 2 previous errors diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr index 4d0e1f2f0f4cc..3efcdf72eee3b 100644 --- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr @@ -4,14 +4,15 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied LL | struct Bar { value: Box } | ----------------------- required by `Bar` ... -LL | / fn bar(&self, x: &Bar) { +LL | fn bar(&self, x: &Bar) { + | ^ - help: consider further restricting `Self`: `where Self: std::cmp::Eq` + | _____| + | | LL | | LL | | // LL | | // Here, Eq ought to be implemented. LL | | } | |_____^ the trait `std::cmp::Eq` is not implemented for `Self` - | - = help: consider adding a `where Self: std::cmp::Eq` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-ret.stderr b/src/test/ui/wf/wf-trait-default-fn-ret.stderr index e82b76b61c4a9..e32630a5a4a40 100644 --- a/src/test/ui/wf/wf-trait-default-fn-ret.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-ret.stderr @@ -4,15 +4,16 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied LL | struct Bar { value: Box } | ----------------------- required by `Bar` ... -LL | / fn bar(&self) -> Bar { +LL | fn bar(&self) -> Bar { + | ^ - help: consider further restricting `Self`: `where Self: std::cmp::Eq` + | _____| + | | LL | | LL | | // LL | | // Here, Eq ought to be implemented. LL | | loop { } LL | | } | |_____^ the trait `std::cmp::Eq` is not implemented for `Self` - | - = help: consider adding a `where Self: std::cmp::Eq` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr index 6504f6698d9b1..a443ff1bb6396 100644 --- a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr @@ -4,14 +4,15 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied LL | trait Bar { } | ---------------------- required by `Bar` ... -LL | / fn bar(&self) where A: Bar { +LL | fn bar(&self) where A: Bar { + | ^ - help: consider further restricting `Self`: `, Self: std::cmp::Eq` + | _____| + | | LL | | LL | | // LL | | // Here, Eq ought to be implemented. LL | | } | |_____^ the trait `std::cmp::Eq` is not implemented for `Self` - | - = help: consider adding a `where Self: std::cmp::Eq` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-arg.stderr b/src/test/ui/wf/wf-trait-fn-arg.stderr index 0887d4b2fcda2..42a28ee676373 100644 --- a/src/test/ui/wf/wf-trait-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-fn-arg.stderr @@ -5,9 +5,10 @@ LL | struct Bar { value: Box } | ----------------------- required by `Bar` ... LL | fn bar(&self, x: &Bar); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` - | - = help: consider adding a `where Self: std::cmp::Eq` bound + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | | + | | help: consider further restricting `Self`: `where Self: std::cmp::Eq` + | the trait `std::cmp::Eq` is not implemented for `Self` error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-ret.stderr b/src/test/ui/wf/wf-trait-fn-ret.stderr index 5555081498c61..7ec4dbe0056b4 100644 --- a/src/test/ui/wf/wf-trait-fn-ret.stderr +++ b/src/test/ui/wf/wf-trait-fn-ret.stderr @@ -5,9 +5,10 @@ LL | struct Bar { value: Box } | ----------------------- required by `Bar` ... LL | fn bar(&self) -> &Bar; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` - | - = help: consider adding a `where Self: std::cmp::Eq` bound + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | | + | | help: consider further restricting `Self`: `where Self: std::cmp::Eq` + | the trait `std::cmp::Eq` is not implemented for `Self` error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-fn-where-clause.stderr index 5e8fd8982390d..256edb5b2ca1d 100644 --- a/src/test/ui/wf/wf-trait-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-trait-fn-where-clause.stderr @@ -5,9 +5,10 @@ LL | struct Bar { value: Box } | ----------------------- required by `Bar` ... LL | fn bar(&self) where Self: Sized, Bar: Copy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` - | - = help: consider adding a `where Self: std::cmp::Eq` bound + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | | + | | help: consider further restricting `Self`: `, Self: std::cmp::Eq` + | the trait `std::cmp::Eq` is not implemented for `Self` error: aborting due to previous error From ca1885de4178abe554f89a1d4556c2a4e742b03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 8 Oct 2019 16:13:05 -0700 Subject: [PATCH 05/16] Update some tests involving `Self` --- .../associated-types-for-unimpl-trait.fixed | 15 ++++++++++ .../associated-types-for-unimpl-trait.rs | 3 ++ .../associated-types-for-unimpl-trait.stderr | 2 +- ...ated-trait-in-method-without-default.fixed | 30 +++++++++++++++++++ ...related-trait-in-method-without-default.rs | 1 + ...ted-trait-in-method-without-default.stderr | 2 +- 6 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed create mode 100644 src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed b/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed new file mode 100644 index 0000000000000..b27d58018c296 --- /dev/null +++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed @@ -0,0 +1,15 @@ +// run-rustfix +#![allow(unused_variables)] + +trait Get { + type Value; + fn get(&self) -> ::Value; +} + +trait Other { + fn uhoh(&self, foo: U, bar: ::Value) where Self: Get{} + //~^ ERROR the trait bound `Self: Get` is not satisfied +} + +fn main() { +} diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.rs b/src/test/ui/associated-types/associated-types-for-unimpl-trait.rs index 5b10d1dc2fdb5..0f6cea8e69fcf 100644 --- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.rs +++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.rs @@ -1,3 +1,6 @@ +// run-rustfix +#![allow(unused_variables)] + trait Get { type Value; fn get(&self) -> ::Value; diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr index 79525e6362f17..f8fc2b37e730f 100644 --- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr +++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-for-unimpl-trait.rs:7:5 + --> $DIR/associated-types-for-unimpl-trait.rs:10:5 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^ diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed new file mode 100644 index 0000000000000..9bc308465ebdd --- /dev/null +++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed @@ -0,0 +1,30 @@ +// run-rustfix +// Check that we get an error when you use `::Value` in +// the trait definition even if there is no default method. + +trait Get { + type Value; +} + +trait Other { + fn okay(&self, foo: U, bar: ::Value) where Self: Get; + //~^ ERROR E0277 +} + +impl Get for () { + type Value = f32; +} + +impl Get for f64 { + type Value = u32; +} + +impl Other for () { + fn okay(&self, _foo: U, _bar: ::Value) { } +} + +impl Other for f64 { + fn okay(&self, _foo: U, _bar: ::Value) { } +} + +fn main() { } diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs index fc38b26f50b62..549fc8fc618e0 100644 --- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs +++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs @@ -1,3 +1,4 @@ +// run-rustfix // Check that we get an error when you use `::Value` in // the trait definition even if there is no default method. diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr index 54daeca425208..cb01488fa34d4 100644 --- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr +++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:9:5 + --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5 | LL | fn okay(&self, foo: U, bar: ::Value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- From b81df6b739c14a2e5d5e1cad2c7ca7952ba947c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 8 Oct 2019 16:13:20 -0700 Subject: [PATCH 06/16] Consider trait aliases --- src/librustc/traits/error_reporting.rs | 3 +++ src/test/ui/traits/trait-alias/trait-alias-wf.stderr | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 6e111089d06d1..77d4e10d4f4e2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1029,6 +1029,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(_, generics), span, .. }) | + hir::Node::Item(hir::Item { + kind: hir::ItemKind::TraitAlias(generics, _), span, .. + }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), span, .. }) | diff --git a/src/test/ui/traits/trait-alias/trait-alias-wf.stderr b/src/test/ui/traits/trait-alias/trait-alias-wf.stderr index ca6d058471667..4355a517bd724 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-wf.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-wf.stderr @@ -4,9 +4,10 @@ error[E0277]: the trait bound `T: Foo` is not satisfied LL | trait A {} | --------------- required by `A` LL | trait B = A; - | ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `T` - | - = help: consider adding a `where T: Foo` bound + | ^^^^^^^^-^^^^^^^^^ + | | | + | | help: consider restricting this bound: `T: Foo` + | the trait `Foo` is not implemented for `T` error: aborting due to previous error From daa8491648d742085bf071169624d99d542a044f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 8 Oct 2019 16:19:39 -0700 Subject: [PATCH 07/16] Update NLL tests --- .../ui/kindck/kindck-impl-type-params.nll.stderr | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr index 25d0e74187f75..82efa83990553 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr @@ -1,42 +1,50 @@ error[E0277]: `T` cannot be sent between threads safely --> $DIR/kindck-impl-type-params.rs:18:13 | +LL | fn f(val: T) { + | - help: consider restricting this bound: `T: std::marker::Send` +LL | let t: S = S(marker::PhantomData); LL | let a = &t as &dyn Gettable; | ^^ `T` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `T` - = help: consider adding a `where T: std::marker::Send` bound = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:18:13 | +LL | fn f(val: T) { + | - help: consider restricting this bound: `T: std::marker::Copy` +LL | let t: S = S(marker::PhantomData); LL | let a = &t as &dyn Gettable; | ^^ the trait `std::marker::Copy` is not implemented for `T` | - = help: consider adding a `where T: std::marker::Copy` bound = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` error[E0277]: `T` cannot be sent between threads safely --> $DIR/kindck-impl-type-params.rs:25:31 | +LL | fn g(val: T) { + | - help: consider restricting this bound: `T: std::marker::Send` +LL | let t: S = S(marker::PhantomData); LL | let a: &dyn Gettable = &t; | ^^ `T` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `T` - = help: consider adding a `where T: std::marker::Send` bound = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:25:31 | +LL | fn g(val: T) { + | - help: consider restricting this bound: `T: std::marker::Copy` +LL | let t: S = S(marker::PhantomData); LL | let a: &dyn Gettable = &t; | ^^ the trait `std::marker::Copy` is not implemented for `T` | - = help: consider adding a `where T: std::marker::Copy` bound = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` From 5cc99eed04005108797fbba82eaf8ef7918051db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 9 Oct 2019 15:07:22 -0700 Subject: [PATCH 08/16] Handle missing projection restriction --- src/librustc/traits/error_reporting.rs | 49 +++++++++++++++---- .../bad-bounds-on-assoc-in-trait.stderr | 18 ++++--- .../associated-types-bound-failure.fixed | 29 +++++++++++ .../associated-types-bound-failure.rs | 2 + .../associated-types-bound-failure.stderr | 7 +-- .../associated-types-unsized.fixed | 14 ++++++ .../associated-types-unsized.rs | 3 ++ .../associated-types-unsized.stderr | 5 +- src/test/ui/issues/issue-22872.stderr | 3 +- src/test/ui/issues/issue-42312.stderr | 5 +- ...typeck-default-trait-impl-assoc-type.fixed | 17 +++++++ .../typeck-default-trait-impl-assoc-type.rs | 2 + ...ypeck-default-trait-impl-assoc-type.stderr | 5 +- 13 files changed, 134 insertions(+), 25 deletions(-) create mode 100644 src/test/ui/associated-types/associated-types-bound-failure.fixed create mode 100644 src/test/ui/associated-types/associated-types-unsized.fixed create mode 100644 src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 77d4e10d4f4e2..2ac691b47aca2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -975,11 +975,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_ref.self_ty(), trait_ref.self_ty().kind, ); - let param_ty = if let ty::Param(param_ty) = &trait_ref.self_ty().kind { - param_ty - } else { - err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); - return; + let (param_ty, projection) = match &trait_ref.self_ty().kind { + ty::Param(param_ty) => (Some(param_ty), None), + ty::Projection(projection) => (None, Some(projection)), + _ => { + err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); + return; + } }; let mut hir_id = body_id; @@ -996,7 +998,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { hir::Node::ImplItem(hir::ImplItem { generics, kind: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, _), .. - }) if param_ty.name.as_str() == "Self" => { + }) if param_ty.map(|p| p.name.as_str() == "Self").unwrap_or(false) => { if !generics.where_clause.predicates.is_empty() { err.span_suggestion( generics.where_clause.span().unwrap().shrink_to_hi(), @@ -1014,6 +1016,34 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } return; } + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(decl, _, generics, _), .. + }) | + hir::Node::TraitItem(hir::TraitItem { + generics, + kind: hir::TraitItemKind::Method(hir::MethodSig { decl, .. }, _), .. + }) | + hir::Node::ImplItem(hir::ImplItem { + generics, + kind: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, _), .. + }) if projection.is_some() => { + if !generics.where_clause.predicates.is_empty() { + err.span_suggestion( + generics.where_clause.span().unwrap().shrink_to_hi(), + "consider further restricting the associated type", + format!(", {}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion( + decl.output.span().shrink_to_hi(), + "consider further restricting the associated type", + format!(" where {}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } + return; + } hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(_, generics), span, .. }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics), span, .. }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(_, generics), span, .. }) | @@ -1036,9 +1066,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), span, .. }) | hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) | - hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) => { + hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) + if param_ty.is_some() => { let restrict_msg = "consider further restricting this bound"; - let param_name = param_ty.name.as_str(); + let param_name = param_ty.unwrap().name.as_str(); for param in &generics.params { if param_name == param.name.ident().as_str() { if param_name.starts_with("impl ") { @@ -1064,7 +1095,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { generics.where_clause.span().unwrap().shrink_to_hi(), &format!( "consider further restricting type parameter `{}`", - param_ty, + param_name, ), format!(", {}", trait_ref.to_predicate()), Applicability::MachineApplicable, diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr index 06e8230aa1589..1795fb5acebe0 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr @@ -9,7 +9,10 @@ LL | impl Case1 for S1 { error[E0277]: `<::C as std::iter::Iterator>::Item` is not an iterator --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 | -LL | / fn assume_case1() { +LL | fn assume_case1() { + | ^ - help: consider further restricting the associated type: `where <::C as std::iter::Iterator>::Item: std::iter::Iterator` + | _| + | | LL | | LL | | LL | | @@ -19,7 +22,6 @@ LL | | } | |_^ `<::C as std::iter::Iterator>::Item` is not an iterator | = help: the trait `std::iter::Iterator` is not implemented for `<::C as std::iter::Iterator>::Item` - = help: consider adding a `where <::C as std::iter::Iterator>::Item: std::iter::Iterator` bound error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 @@ -27,7 +29,10 @@ error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be sent be LL | trait Case1 { | ----------- required by `Case1` ... -LL | / fn assume_case1() { +LL | fn assume_case1() { + | ^ - help: consider further restricting the associated type: `where <::C as std::iter::Iterator>::Item: std::marker::Send` + | _| + | | LL | | LL | | LL | | @@ -37,7 +42,6 @@ LL | | } | |_^ `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `<::C as std::iter::Iterator>::Item` - = help: consider adding a `where <::C as std::iter::Iterator>::Item: std::marker::Send` bound error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 @@ -45,7 +49,10 @@ error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be shared LL | trait Case1 { | ----------- required by `Case1` ... -LL | / fn assume_case1() { +LL | fn assume_case1() { + | ^ - help: consider further restricting the associated type: `where <::C as std::iter::Iterator>::Item: std::marker::Sync` + | _| + | | LL | | LL | | LL | | @@ -55,7 +62,6 @@ LL | | } | |_^ `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `<::C as std::iter::Iterator>::Item` - = help: consider adding a `where <::C as std::iter::Iterator>::Item: std::marker::Sync` bound error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 diff --git a/src/test/ui/associated-types/associated-types-bound-failure.fixed b/src/test/ui/associated-types/associated-types-bound-failure.fixed new file mode 100644 index 0000000000000..68ee38d16b3f3 --- /dev/null +++ b/src/test/ui/associated-types/associated-types-bound-failure.fixed @@ -0,0 +1,29 @@ +// run-rustfix +// Test equality constraints on associated types in a where clause. +#![allow(dead_code)] + +pub trait ToInt { + fn to_int(&self) -> isize; +} + +pub trait GetToInt +{ + type R; + + fn get(&self) -> ::R; +} + +fn foo(g: G) -> isize + where G : GetToInt, ::R: ToInt +{ + ToInt::to_int(&g.get()) //~ ERROR E0277 +} + +fn bar(g: G) -> isize + where G::R : ToInt +{ + ToInt::to_int(&g.get()) // OK +} + +pub fn main() { +} diff --git a/src/test/ui/associated-types/associated-types-bound-failure.rs b/src/test/ui/associated-types/associated-types-bound-failure.rs index 883ac363b44e5..31e073cc7a8bd 100644 --- a/src/test/ui/associated-types/associated-types-bound-failure.rs +++ b/src/test/ui/associated-types/associated-types-bound-failure.rs @@ -1,4 +1,6 @@ +// run-rustfix // Test equality constraints on associated types in a where clause. +#![allow(dead_code)] pub trait ToInt { fn to_int(&self) -> isize; diff --git a/src/test/ui/associated-types/associated-types-bound-failure.stderr b/src/test/ui/associated-types/associated-types-bound-failure.stderr index 85acf134d51d5..c420c86a2758f 100644 --- a/src/test/ui/associated-types/associated-types-bound-failure.stderr +++ b/src/test/ui/associated-types/associated-types-bound-failure.stderr @@ -1,13 +1,14 @@ error[E0277]: the trait bound `::R: ToInt` is not satisfied - --> $DIR/associated-types-bound-failure.rs:17:19 + --> $DIR/associated-types-bound-failure.rs:19:19 | LL | fn to_int(&self) -> isize; | -------------------------- required by `ToInt::to_int` ... +LL | where G : GetToInt + | - help: consider further restricting the associated type: `, ::R: ToInt` +LL | { LL | ToInt::to_int(&g.get()) | ^^^^^^^^ the trait `ToInt` is not implemented for `::R` - | - = help: consider adding a `where ::R: ToInt` bound error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-unsized.fixed b/src/test/ui/associated-types/associated-types-unsized.fixed new file mode 100644 index 0000000000000..385de541e560d --- /dev/null +++ b/src/test/ui/associated-types/associated-types-unsized.fixed @@ -0,0 +1,14 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + +trait Get { + type Value: ?Sized; + fn get(&self) -> ::Value; +} + +fn foo(t: T) where ::Value: std::marker::Sized{ + let x = t.get(); //~ ERROR the size for values of type +} + +fn main() { +} diff --git a/src/test/ui/associated-types/associated-types-unsized.rs b/src/test/ui/associated-types/associated-types-unsized.rs index a9bc24e44d165..bdba4c7ff16a1 100644 --- a/src/test/ui/associated-types/associated-types-unsized.rs +++ b/src/test/ui/associated-types/associated-types-unsized.rs @@ -1,3 +1,6 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + trait Get { type Value: ?Sized; fn get(&self) -> ::Value; diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr index b5db9743932e9..18595721bceef 100644 --- a/src/test/ui/associated-types/associated-types-unsized.stderr +++ b/src/test/ui/associated-types/associated-types-unsized.stderr @@ -1,12 +1,13 @@ error[E0277]: the size for values of type `::Value` cannot be known at compilation time - --> $DIR/associated-types-unsized.rs:7:9 + --> $DIR/associated-types-unsized.rs:10:9 | +LL | fn foo(t: T) { + | - help: consider further restricting the associated type: `where ::Value: std::marker::Sized` LL | let x = t.get(); | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `::Value` = note: to learn more, visit - = help: consider adding a `where ::Value: std::marker::Sized` bound = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr index fc5de23752b3e..283a5e04a8b6f 100644 --- a/src/test/ui/issues/issue-22872.stderr +++ b/src/test/ui/issues/issue-22872.stderr @@ -1,11 +1,12 @@ error[E0277]: `

>::Item` is not an iterator --> $DIR/issue-22872.rs:20:40 | +LL | fn push_process

(process: P) where P: Process<'static> { + | - help: consider further restricting the associated type: `,

>::Item: std::iter::Iterator` LL | let _: Box Wrap<'b>> = Box::new(Wrapper(process)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `

>::Item` is not an iterator | = help: the trait `std::iter::Iterator` is not implemented for `

>::Item` - = help: consider adding a `where

>::Item: std::iter::Iterator` bound = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper

` = note: required for the cast to the object type `dyn for<'b> Wrap<'b>` diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr index bfdc4272fb308..6688203147eaf 100644 --- a/src/test/ui/issues/issue-42312.stderr +++ b/src/test/ui/issues/issue-42312.stderr @@ -2,11 +2,12 @@ error[E0277]: the size for values of type `::Target` ca --> $DIR/issue-42312.rs:4:29 | LL | fn baz(_: Self::Target) where Self: Deref {} - | ^ doesn't have a size known at compile-time + | ^ - help: consider further restricting the associated type: `, ::Target: std::marker::Sized` + | | + | doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `::Target` = note: to learn more, visit - = help: consider adding a `where ::Target: std::marker::Sized` bound = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed new file mode 100644 index 0000000000000..757d8b8a235a5 --- /dev/null +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed @@ -0,0 +1,17 @@ +// run-rustfix +// Test that we do not consider associated types to be sendable without +// some applicable trait bound (and we don't ICE). +#![allow(dead_code)] + +trait Trait { + type AssocType; + fn dummy(&self) { } +} +fn bar() where ::AssocType: std::marker::Send{ + is_send::(); //~ ERROR E0277 +} + +fn is_send() { +} + +fn main() { } diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs index d648353938674..bafc1657737f4 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs @@ -1,5 +1,7 @@ +// run-rustfix // Test that we do not consider associated types to be sendable without // some applicable trait bound (and we don't ICE). +#![allow(dead_code)] trait Trait { type AssocType; diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr index b842d0ae1a248..dd6dcbe2ef574 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr @@ -1,6 +1,8 @@ error[E0277]: `::AssocType` cannot be sent between threads safely - --> $DIR/typeck-default-trait-impl-assoc-type.rs:9:5 + --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5 | +LL | fn bar() { + | - help: consider further restricting the associated type: `where ::AssocType: std::marker::Send` LL | is_send::(); | ^^^^^^^^^^^^^^^^^^^^^^^ `::AssocType` cannot be sent between threads safely ... @@ -8,7 +10,6 @@ LL | fn is_send() { | ------- ---- required by this bound in `is_send` | = help: the trait `std::marker::Send` is not implemented for `::AssocType` - = help: consider adding a `where ::AssocType: std::marker::Send` bound error: aborting due to previous error From bc744bca9063cd9145fceed4ba7ef14cab0ecdd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 9 Oct 2019 15:54:23 -0700 Subject: [PATCH 09/16] Suggest associated bound restrictions in `impl`s --- src/librustc/hir/mod.rs | 6 +++ src/librustc/traits/error_reporting.rs | 18 ++++++++ src/test/ui/issues/issue-38821.stderr | 5 ++- .../missing-assoc-type-bound-restriction.rs | 25 +++++++++++ ...issing-assoc-type-bound-restriction.stderr | 43 +++++++++++++++++++ 5 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs create mode 100644 src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 7350f89018be2..fa0f620530de1 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -669,6 +669,12 @@ impl WhereClause { Some(self.span) } } + + /// The `WhereClause` under normal circumstances points at either the predicates or the empty + /// space where the `where` clause should be. Only of use for diagnostic suggestions. + pub fn span_for_predicates_or_empty_place(&self) -> Span { + self.span + } } /// A single predicate in a where-clause. diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 2ac691b47aca2..91106d35a7ee1 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1044,6 +1044,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } return; } + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(_, _, _, generics, ..), .. + }) if projection.is_some() => { + err.span_suggestion( + generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(), + "consider further restricting the associated type", + format!( + "{} {}", if generics.where_clause.predicates.is_empty() { + " where" + } else { + " ," + }, + trait_ref.to_predicate(), + ), + Applicability::MachineApplicable, + ); + return; + } hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(_, generics), span, .. }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics), span, .. }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(_, generics), span, .. }) | diff --git a/src/test/ui/issues/issue-38821.stderr b/src/test/ui/issues/issue-38821.stderr index dbd204ec299d7..3e2af7c44e4a2 100644 --- a/src/test/ui/issues/issue-38821.stderr +++ b/src/test/ui/issues/issue-38821.stderr @@ -2,9 +2,10 @@ error[E0277]: the trait bound `::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:17 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^ the trait `NotNull` is not implemented for `::SqlType` + | ^^^^- help: consider further restricting the associated type: `, ::SqlType: NotNull` + | | + | the trait `NotNull` is not implemented for `::SqlType` | - = help: consider adding a `where ::SqlType: NotNull` bound = note: required because of the requirements on the impl of `IntoNullable` for `::SqlType` error: aborting due to previous error diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs new file mode 100644 index 0000000000000..265ccb3125ca3 --- /dev/null +++ b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs @@ -0,0 +1,25 @@ +// Running rustfix would cause the same suggestion to be applied multiple times, which results in +// invalid code. + +trait Parent { + type Ty; + type Assoc: Child; +} + +trait Child {} + +struct ChildWrapper(T); + +impl Child for ChildWrapper where T: Child {} + +struct ParentWrapper(T); + +impl> Parent for ParentWrapper { + //~^ ERROR the trait bound `::Assoc: Child` is not satisfied + //~| ERROR the trait bound `::Assoc: Child` is not satisfied + type Ty = A; + type Assoc = ChildWrapper; + //~^ ERROR the trait bound `::Assoc: Child` is not satisfied +} + +fn main() {} diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr new file mode 100644 index 0000000000000..bdea8ab97e5b5 --- /dev/null +++ b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr @@ -0,0 +1,43 @@ +error[E0277]: the trait bound `::Assoc: Child` is not satisfied + --> $DIR/missing-assoc-type-bound-restriction.rs:17:1 + | +LL | trait Parent { + | ------------ required by `Parent` +... +LL | impl> Parent for ParentWrapper { + | ^ - help: consider further restricting the associated type: `where ::Assoc: Child` + | _| + | | +LL | | +LL | | +LL | | type Ty = A; +LL | | type Assoc = ChildWrapper; +LL | | +LL | | } + | |_^ the trait `Child` is not implemented for `::Assoc` + +error[E0277]: the trait bound `::Assoc: Child` is not satisfied + --> $DIR/missing-assoc-type-bound-restriction.rs:17:28 + | +LL | impl> Parent for ParentWrapper { + | ^^^^^^ - help: consider further restricting the associated type: `where ::Assoc: Child` + | | + | the trait `Child` is not implemented for `::Assoc` + | + = note: required because of the requirements on the impl of `Child` for `ChildWrapper<::Assoc>` + +error[E0277]: the trait bound `::Assoc: Child` is not satisfied + --> $DIR/missing-assoc-type-bound-restriction.rs:21:5 + | +LL | trait Parent { + | ------------ required by `Parent` +... +LL | impl> Parent for ParentWrapper { + | - help: consider further restricting the associated type: `where ::Assoc: Child` +... +LL | type Assoc = ChildWrapper; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Child` is not implemented for `::Assoc` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. From ab7d8f0f5a8624d583989b76015254fff2f59cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 10 Oct 2019 09:50:45 -0700 Subject: [PATCH 10/16] Deduplicate some code and apply review comments --- src/librustc/traits/error_reporting.rs | 195 +++++++++--------- .../bad-bounds-on-assoc-in-trait.stderr | 6 +- .../associated-types-bound-failure.fixed | 2 +- .../associated-types-for-unimpl-trait.fixed | 2 +- .../associated-types-for-unimpl-trait.stderr | 6 +- ...ated-types-no-suitable-supertrait-2.stderr | 6 +- ...ciated-types-no-suitable-supertrait.stderr | 6 +- ...ated-trait-in-method-without-default.fixed | 2 +- .../associated-types-unsized.fixed | 2 +- .../associated-types-unsized.stderr | 2 +- ...typeck-default-trait-impl-assoc-type.fixed | 2 +- ...ypeck-default-trait-impl-assoc-type.stderr | 2 +- .../wf/wf-trait-associated-type-trait.stderr | 7 +- src/test/ui/wf/wf-trait-default-fn-arg.stderr | 2 +- 14 files changed, 117 insertions(+), 125 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 91106d35a7ee1..abf265be7c50a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -984,84 +984,66 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } }; + let mut suggest_restriction = |generics: &hir::Generics, msg| { + err.span_suggestion( + generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(), + &format!("consider further restricting {}", msg), + format!( + "{} {} ", + if !generics.where_clause.predicates.is_empty() { + "," + } else { + " where" + }, + trait_ref.to_predicate(), + ), + Applicability::MachineApplicable, + ); + }; + + // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we + // don't suggest `T: Sized + ?Sized`. let mut hir_id = body_id; while let Some(node) = self.tcx.hir().find(hir_id) { - debug!("suggest_restricting_param_bound node={:?}", node); match node { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(decl, _, generics, _), .. + kind: hir::ItemKind::Fn(_, _, generics, _), .. }) | hir::Node::TraitItem(hir::TraitItem { generics, - kind: hir::TraitItemKind::Method(hir::MethodSig { decl, .. }, _), .. + kind: hir::TraitItemKind::Method(..), .. }) | hir::Node::ImplItem(hir::ImplItem { generics, - kind: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, _), .. - }) if param_ty.map(|p| p.name.as_str() == "Self").unwrap_or(false) => { - if !generics.where_clause.predicates.is_empty() { - err.span_suggestion( - generics.where_clause.span().unwrap().shrink_to_hi(), - "consider further restricting `Self`", - format!(", {}", trait_ref.to_predicate()), - Applicability::MachineApplicable, - ); - } else { - err.span_suggestion( - decl.output.span().shrink_to_hi(), - "consider further restricting `Self`", - format!(" where {}", trait_ref.to_predicate()), - Applicability::MachineApplicable, - ); - } + kind: hir::ImplItemKind::Method(..), .. + }) if param_ty.map_or(false, |p| p.name.as_str() == "Self") => { + // Restricting `Self` for a single method. + suggest_restriction(&generics, "`Self`"); return; } + hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(decl, _, generics, _), .. + kind: hir::ItemKind::Fn(_, _, generics, _), .. }) | hir::Node::TraitItem(hir::TraitItem { generics, - kind: hir::TraitItemKind::Method(hir::MethodSig { decl, .. }, _), .. + kind: hir::TraitItemKind::Method(..), .. }) | hir::Node::ImplItem(hir::ImplItem { generics, - kind: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, _), .. - }) if projection.is_some() => { - if !generics.where_clause.predicates.is_empty() { - err.span_suggestion( - generics.where_clause.span().unwrap().shrink_to_hi(), - "consider further restricting the associated type", - format!(", {}", trait_ref.to_predicate()), - Applicability::MachineApplicable, - ); - } else { - err.span_suggestion( - decl.output.span().shrink_to_hi(), - "consider further restricting the associated type", - format!(" where {}", trait_ref.to_predicate()), - Applicability::MachineApplicable, - ); - } - return; - } + kind: hir::ImplItemKind::Method(..), .. + }) | + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Trait(_, _, generics, _, _), .. + }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_, _, _, generics, ..), .. }) if projection.is_some() => { - err.span_suggestion( - generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(), - "consider further restricting the associated type", - format!( - "{} {}", if generics.where_clause.predicates.is_empty() { - " where" - } else { - " ," - }, - trait_ref.to_predicate(), - ), - Applicability::MachineApplicable, - ); + // Missing associated type bound. + suggest_restriction(&generics, "the associated type"); return; } + hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(_, generics), span, .. }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics), span, .. }) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(_, generics), span, .. }) | @@ -1086,73 +1068,82 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) | hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) if param_ty.is_some() => { + // Missing generic type parameter bound. let restrict_msg = "consider further restricting this bound"; let param_name = param_ty.unwrap().name.as_str(); - for param in &generics.params { - if param_name == param.name.ident().as_str() { - if param_name.starts_with("impl ") { + for param in generics.params.iter().filter(|p| { + param_name == p.name.ident().as_str() + }) { + if param_name.starts_with("impl ") { + // `impl Trait` in argument: + // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}` + err.span_suggestion( + param.span, + restrict_msg, + // `impl CurrentTrait + MissingTrait` + format!("{} + {}", param.name.ident(), trait_ref), + Applicability::MachineApplicable, + ); + } else { + if generics.where_clause.predicates.is_empty() && + param.bounds.is_empty() + { + // If there are no bounds whatsoever, suggest adding a constraint + // to the type parameter: + // `fn foo(t: T) {}` → `fn foo(t: T) {}` err.span_suggestion( param.span, - restrict_msg, - // `impl CurrentTrait + MissingTrait` - format!("{} + {}", param.name.ident(), trait_ref), + "consider restricting this bound", + format!("{}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } else if !generics.where_clause.predicates.is_empty() { + // There is a `where` clause, so suggest expanding it: + // `fn foo(t: T) where T: Debug {}` → + // `fn foo(t: T, x: X) {}` → `fn foo(t: T) {}` + // `fn foo(t: T) {}` → `fn foo(t: T) {}` + let sp = param.span.with_hi(span.hi()); + let span = self.tcx.sess.source_map() + .span_through_char(sp, ':'); + if sp != param.span && sp != span { + // Only suggest if we have high certainty that the span + // covers the colon in `foo`. + err.span_suggestion(span, restrict_msg, format!( + "{} + ", + trait_ref.to_predicate(), + ), Applicability::MachineApplicable); } else { - let sp = param.span.with_hi(span.hi()); - let span = self.tcx.sess.source_map() - .span_through_char(sp, ':'); - if sp != param.span && sp != span { - // Only suggest if we have high certainty that the span - // covers the colon in `foo`. - err.span_suggestion(span, restrict_msg, format!( - "{} + ", - trait_ref.to_predicate(), - ), Applicability::MachineApplicable); - } else { - err.span_label(param.span, &format!( - "consider adding a `where {}` bound", - trait_ref.to_predicate(), - )); - } + err.span_label(param.span, &format!( + "consider adding a `where {}` bound", + trait_ref.to_predicate(), + )); } } - return; } + return; } } + hir::Node::Crate => return, + _ => {} } hir_id = self.tcx.hir().get_parent_item(hir_id); } - // FIXME: Add special check for `?Sized` so we don't suggest `T: Sized + ?Sized`. - - // Fallback in case we didn't find the type argument. Can happen on associated types - // bounds and when `Self` needs to be restricted, like in the ui test - // `associated-types-projection-to-unrelated-trait-in-method-without-default.rs`. - err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); } /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr index 1795fb5acebe0..9f6a73cfe3910 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr @@ -10,7 +10,7 @@ error[E0277]: `<::C as std::iter::Iterator>::Item` is not an iterato --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 | LL | fn assume_case1() { - | ^ - help: consider further restricting the associated type: `where <::C as std::iter::Iterator>::Item: std::iter::Iterator` + | ^ - help: consider further restricting the associated type: `where <::C as std::iter::Iterator>::Item: std::iter::Iterator` | _| | | LL | | @@ -30,7 +30,7 @@ LL | trait Case1 { | ----------- required by `Case1` ... LL | fn assume_case1() { - | ^ - help: consider further restricting the associated type: `where <::C as std::iter::Iterator>::Item: std::marker::Send` + | ^ - help: consider further restricting the associated type: `where <::C as std::iter::Iterator>::Item: std::marker::Send` | _| | | LL | | @@ -50,7 +50,7 @@ LL | trait Case1 { | ----------- required by `Case1` ... LL | fn assume_case1() { - | ^ - help: consider further restricting the associated type: `where <::C as std::iter::Iterator>::Item: std::marker::Sync` + | ^ - help: consider further restricting the associated type: `where <::C as std::iter::Iterator>::Item: std::marker::Sync` | _| | | LL | | diff --git a/src/test/ui/associated-types/associated-types-bound-failure.fixed b/src/test/ui/associated-types/associated-types-bound-failure.fixed index 68ee38d16b3f3..cc47f31d00456 100644 --- a/src/test/ui/associated-types/associated-types-bound-failure.fixed +++ b/src/test/ui/associated-types/associated-types-bound-failure.fixed @@ -14,7 +14,7 @@ pub trait GetToInt } fn foo(g: G) -> isize - where G : GetToInt, ::R: ToInt + where G : GetToInt, ::R: ToInt { ToInt::to_int(&g.get()) //~ ERROR E0277 } diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed b/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed index b27d58018c296..aa23326506f63 100644 --- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed +++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed @@ -7,7 +7,7 @@ trait Get { } trait Other { - fn uhoh(&self, foo: U, bar: ::Value) where Self: Get{} + fn uhoh(&self, foo: U, bar: ::Value) where Self: Get {} //~^ ERROR the trait bound `Self: Get` is not satisfied } diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr index f8fc2b37e730f..83d5390417e77 100644 --- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr +++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr @@ -2,9 +2,9 @@ error[E0277]: the trait bound `Self: Get` is not satisfied --> $DIR/associated-types-for-unimpl-trait.rs:10:5 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^ - | | | - | | help: consider further restricting `Self`: `where Self: Get` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | | + | | help: consider further restricting `Self`: `where Self: Get` | the trait `Get` is not implemented for `Self` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr index 43950defc7cb9..6aa0403088d3c 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr @@ -2,9 +2,9 @@ error[E0277]: the trait bound `Self: Get` is not satisfied --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^ - | | | - | | help: consider further restricting `Self`: `where Self: Get` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | | + | | help: consider further restricting `Self`: `where Self: Get` | the trait `Get` is not implemented for `Self` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr index 82e366dbea4b4..8c242be979611 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr @@ -2,9 +2,9 @@ error[E0277]: the trait bound `Self: Get` is not satisfied --> $DIR/associated-types-no-suitable-supertrait.rs:17:5 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^ - | | | - | | help: consider further restricting `Self`: `where Self: Get` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | | + | | help: consider further restricting `Self`: `where Self: Get` | the trait `Get` is not implemented for `Self` error[E0277]: the trait bound `(T, U): Get` is not satisfied diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed index 9bc308465ebdd..f357045a456e6 100644 --- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed +++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed @@ -7,7 +7,7 @@ trait Get { } trait Other { - fn okay(&self, foo: U, bar: ::Value) where Self: Get; + fn okay(&self, foo: U, bar: ::Value) where Self: Get ; //~^ ERROR E0277 } diff --git a/src/test/ui/associated-types/associated-types-unsized.fixed b/src/test/ui/associated-types/associated-types-unsized.fixed index 385de541e560d..f780d171fee8e 100644 --- a/src/test/ui/associated-types/associated-types-unsized.fixed +++ b/src/test/ui/associated-types/associated-types-unsized.fixed @@ -6,7 +6,7 @@ trait Get { fn get(&self) -> ::Value; } -fn foo(t: T) where ::Value: std::marker::Sized{ +fn foo(t: T) where ::Value: std::marker::Sized { let x = t.get(); //~ ERROR the size for values of type } diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr index 18595721bceef..2352ac4ad3822 100644 --- a/src/test/ui/associated-types/associated-types-unsized.stderr +++ b/src/test/ui/associated-types/associated-types-unsized.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `::Value` cannot be known at --> $DIR/associated-types-unsized.rs:10:9 | LL | fn foo(t: T) { - | - help: consider further restricting the associated type: `where ::Value: std::marker::Sized` + | - help: consider further restricting the associated type: `where ::Value: std::marker::Sized` LL | let x = t.get(); | ^ doesn't have a size known at compile-time | diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed index 757d8b8a235a5..7a108d880bed3 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed @@ -7,7 +7,7 @@ trait Trait { type AssocType; fn dummy(&self) { } } -fn bar() where ::AssocType: std::marker::Send{ +fn bar() where ::AssocType: std::marker::Send { is_send::(); //~ ERROR E0277 } diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr index dd6dcbe2ef574..2e54cdf01320d 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr @@ -2,7 +2,7 @@ error[E0277]: `::AssocType` cannot be sent between threads safely --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5 | LL | fn bar() { - | - help: consider further restricting the associated type: `where ::AssocType: std::marker::Send` + | - help: consider further restricting the associated type: `where ::AssocType: std::marker::Send` LL | is_send::(); | ^^^^^^^^^^^^^^^^^^^^^^^ `::AssocType` cannot be sent between threads safely ... diff --git a/src/test/ui/wf/wf-trait-associated-type-trait.stderr b/src/test/ui/wf/wf-trait-associated-type-trait.stderr index d8ab955048239..93cb948cdbfcb 100644 --- a/src/test/ui/wf/wf-trait-associated-type-trait.stderr +++ b/src/test/ui/wf/wf-trait-associated-type-trait.stderr @@ -3,11 +3,12 @@ error[E0277]: the trait bound `::Type1: std::marker::Copy` is | LL | struct IsCopy { x: T } | --------------------- required by `IsCopy` -... +LL | +LL | trait SomeTrait { + | - help: consider further restricting the associated type: `where ::Type1: std::marker::Copy` +LL | type Type1; LL | type Type2 = IsCopy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `::Type1` - | - = help: consider adding a `where ::Type1: std::marker::Copy` bound error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr index 3efcdf72eee3b..9f3545b9c6a6b 100644 --- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr @@ -5,7 +5,7 @@ LL | struct Bar { value: Box } | ----------------------- required by `Bar` ... LL | fn bar(&self, x: &Bar) { - | ^ - help: consider further restricting `Self`: `where Self: std::cmp::Eq` + | ^ - help: consider further restricting `Self`: `where Self: std::cmp::Eq` | _____| | | LL | | From 39a9e2ecba1797ef196725c25f48746834d8ac8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 10 Oct 2019 13:17:51 -0700 Subject: [PATCH 11/16] Remove useless `help` --- src/librustc/traits/error_reporting.rs | 11 +---------- src/test/ui/partialeq_help.stderr | 1 - src/test/ui/traits/trait-suggest-where-clause.stderr | 2 -- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index abf265be7c50a..9931a2517f112 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -969,19 +969,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_ref: &ty::PolyTraitRef<'_>, body_id: hir::HirId, ) { - debug!( - "suggest_restricting_param_bound trait_ref={:?} ty={:?} ({:?})", - trait_ref, - trait_ref.self_ty(), - trait_ref.self_ty().kind, - ); let (param_ty, projection) = match &trait_ref.self_ty().kind { ty::Param(param_ty) => (Some(param_ty), None), ty::Projection(projection) => (None, Some(projection)), - _ => { - err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); - return; - } + _ => return, }; let mut suggest_restriction = |generics: &hir::Generics, msg| { diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr index 9021bd30a7781..6acc09b62c811 100644 --- a/src/test/ui/partialeq_help.stderr +++ b/src/test/ui/partialeq_help.stderr @@ -5,7 +5,6 @@ LL | a == b; | ^^ no implementation for `&T == T` | = help: the trait `std::cmp::PartialEq` is not implemented for `&T` - = help: consider adding a `where &T: std::cmp::PartialEq` bound error: aborting due to previous error diff --git a/src/test/ui/traits/trait-suggest-where-clause.stderr b/src/test/ui/traits/trait-suggest-where-clause.stderr index bc9948064a30c..f1004ea9dc6ee 100644 --- a/src/test/ui/traits/trait-suggest-where-clause.stderr +++ b/src/test/ui/traits/trait-suggest-where-clause.stderr @@ -39,7 +39,6 @@ error[E0277]: the trait bound `u64: std::convert::From` is not satisfied LL | >::from; | ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From` is not implemented for `u64` | - = help: consider adding a `where u64: std::convert::From` bound = note: required by `std::convert::From::from` error[E0277]: the trait bound `u64: std::convert::From<::Item>` is not satisfied @@ -48,7 +47,6 @@ error[E0277]: the trait bound `u64: std::convert::From<::Item>>::from; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<::Item>` is not implemented for `u64` | - = help: consider adding a `where u64: std::convert::From<::Item>` bound = note: required by `std::convert::From::from` error[E0277]: the trait bound `Misc<_>: std::convert::From` is not satisfied From 8cabb425415028e3abad56034e7daef6f05343bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 10 Oct 2019 13:22:05 -0700 Subject: [PATCH 12/16] Remove trailing whitespace --- src/librustc/traits/error_reporting.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 9931a2517f112..66d844ee808ec 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1066,7 +1066,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { param_name == p.name.ident().as_str() }) { if param_name.starts_with("impl ") { - // `impl Trait` in argument: + // `impl Trait` in argument: // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}` err.span_suggestion( param.span, From 9c525ee95bcc99730003e2d4bbb58520337bdefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 15 Oct 2019 13:16:33 -0700 Subject: [PATCH 13/16] review comments --- src/librustc/traits/error_reporting.rs | 110 ++++++++++++------------- 1 file changed, 51 insertions(+), 59 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 66d844ee808ec..8e9a350030c4d 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -969,9 +969,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_ref: &ty::PolyTraitRef<'_>, body_id: hir::HirId, ) { - let (param_ty, projection) = match &trait_ref.self_ty().kind { - ty::Param(param_ty) => (Some(param_ty), None), - ty::Projection(projection) => (None, Some(projection)), + let self_ty = trait_ref.self_ty(); + let (param_ty, projection) = match &self_ty.kind { + ty::Param(_) => (true, None), + ty::Projection(projection) => (false, Some(projection)), _ => return, }; @@ -997,17 +998,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut hir_id = body_id; while let Some(node) = self.tcx.hir().find(hir_id) { match node { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(_, _, generics, _), .. - }) | hir::Node::TraitItem(hir::TraitItem { generics, kind: hir::TraitItemKind::Method(..), .. - }) | - hir::Node::ImplItem(hir::ImplItem { - generics, - kind: hir::ImplItemKind::Method(..), .. - }) if param_ty.map_or(false, |p| p.name.as_str() == "Self") => { + }) if param_ty && self_ty == self.tcx.types.self_param => { // Restricting `Self` for a single method. suggest_restriction(&generics, "`Self`"); return; @@ -1058,12 +1052,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) | hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) | hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) - if param_ty.is_some() => { + if param_ty => { // Missing generic type parameter bound. let restrict_msg = "consider further restricting this bound"; - let param_name = param_ty.unwrap().name.as_str(); + let param_name = self_ty.to_string(); for param in generics.params.iter().filter(|p| { - param_name == p.name.ident().as_str() + ¶m_name == p.name.ident().as_str() }) { if param_name.starts_with("impl ") { // `impl Trait` in argument: @@ -1075,53 +1069,51 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { format!("{} + {}", param.name.ident(), trait_ref), Applicability::MachineApplicable, ); - } else { - if generics.where_clause.predicates.is_empty() && + } else if generics.where_clause.predicates.is_empty() && param.bounds.is_empty() - { - // If there are no bounds whatsoever, suggest adding a constraint - // to the type parameter: - // `fn foo(t: T) {}` → `fn foo(t: T) {}` - err.span_suggestion( - param.span, - "consider restricting this bound", - format!("{}", trait_ref.to_predicate()), - Applicability::MachineApplicable, - ); - } else if !generics.where_clause.predicates.is_empty() { - // There is a `where` clause, so suggest expanding it: - // `fn foo(t: T) where T: Debug {}` → - // `fn foo(t: T) {}` → `fn foo(t: T) {}` + err.span_suggestion( + param.span, + "consider restricting this bound", + format!("{}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } else if !generics.where_clause.predicates.is_empty() { + // There is a `where` clause, so suggest expanding it: + // `fn foo(t: T) where T: Debug {}` → + // `fn foo(t: T) where T: Debug, T: Trait {}` + err.span_suggestion( + generics.where_clause.span().unwrap().shrink_to_hi(), + &format!( + "consider further restricting type parameter `{}`", + param_name, + ), + format!(", {}", trait_ref.to_predicate()), + Applicability::MachineApplicable, + ); + } else { + // If there is no `where` clause lean towards constraining to the + // type parameter: + // `fn foo(t: T, x: X) {}` → `fn foo(t: T) {}` + // `fn foo(t: T) {}` → `fn foo(t: T) {}` + let sp = param.span.with_hi(span.hi()); + let span = self.tcx.sess.source_map() + .span_through_char(sp, ':'); + if sp != param.span && sp != span { + // Only suggest if we have high certainty that the span + // covers the colon in `foo`. + err.span_suggestion(span, restrict_msg, format!( + "{} + ", + trait_ref.to_predicate(), + ), Applicability::MachineApplicable); } else { - // If there is no `where` clause lean towards constraining to the - // type parameter: - // `fn foo(t: T, x: X) {}` → `fn foo(t: T) {}` - // `fn foo(t: T) {}` → `fn foo(t: T) {}` - let sp = param.span.with_hi(span.hi()); - let span = self.tcx.sess.source_map() - .span_through_char(sp, ':'); - if sp != param.span && sp != span { - // Only suggest if we have high certainty that the span - // covers the colon in `foo`. - err.span_suggestion(span, restrict_msg, format!( - "{} + ", - trait_ref.to_predicate(), - ), Applicability::MachineApplicable); - } else { - err.span_label(param.span, &format!( - "consider adding a `where {}` bound", - trait_ref.to_predicate(), - )); - } + err.span_label(param.span, &format!( + "consider adding a `where {}` bound", + trait_ref.to_predicate(), + )); } } return; From 9ed463a7404f7f3ecf65ca270f360b2da90b467a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 15 Oct 2019 13:29:07 -0700 Subject: [PATCH 14/16] Do not suggest restriction on spans originating in macros --- src/librustc/traits/error_reporting.rs | 31 ++++++++++++++------------ src/test/ui/issues/issue-38821.stderr | 4 +--- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8e9a350030c4d..d5f22afa9afc2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -977,20 +977,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let mut suggest_restriction = |generics: &hir::Generics, msg| { - err.span_suggestion( - generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(), - &format!("consider further restricting {}", msg), - format!( - "{} {} ", - if !generics.where_clause.predicates.is_empty() { - "," - } else { - " where" - }, - trait_ref.to_predicate(), - ), - Applicability::MachineApplicable, - ); + let span = generics.where_clause.span_for_predicates_or_empty_place(); + if !span.from_expansion() && span.desugaring_kind().is_none() { + err.span_suggestion( + generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(), + &format!("consider further restricting {}", msg), + format!( + "{} {} ", + if !generics.where_clause.predicates.is_empty() { + "," + } else { + " where" + }, + trait_ref.to_predicate(), + ), + Applicability::MachineApplicable, + ); + } }; // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we diff --git a/src/test/ui/issues/issue-38821.stderr b/src/test/ui/issues/issue-38821.stderr index 3e2af7c44e4a2..0687fc940dec1 100644 --- a/src/test/ui/issues/issue-38821.stderr +++ b/src/test/ui/issues/issue-38821.stderr @@ -2,9 +2,7 @@ error[E0277]: the trait bound `::SqlType: NotNull` is not sat --> $DIR/issue-38821.rs:23:17 | LL | #[derive(Debug, Copy, Clone)] - | ^^^^- help: consider further restricting the associated type: `, ::SqlType: NotNull` - | | - | the trait `NotNull` is not implemented for `::SqlType` + | ^^^^ the trait `NotNull` is not implemented for `::SqlType` | = note: required because of the requirements on the impl of `IntoNullable` for `::SqlType` From 9ecd1d276732b301fff85a1e660771691db23dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 15 Oct 2019 13:29:26 -0700 Subject: [PATCH 15/16] Simplify code --- src/librustc_typeck/check/demand.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index d92ea7fd49a72..677e2ea356628 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -350,11 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the span is from a macro, then it's hard to extract the text // and make a good suggestion, so don't bother. - let is_desugaring = match sp.desugaring_kind() { - Some(k) => sp.is_desugaring(k), - None => false - }; - let is_macro = sp.from_expansion() && !is_desugaring; + let is_macro = sp.from_expansion() && sp.desugaring_kind().is_none(); // `ExprKind::DropTemps` is semantically irrelevant for these suggestions. let expr = expr.peel_drop_temps(); From c6dce7802dc49a2e4b6049ad8971ba6f18252e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 15 Oct 2019 14:07:32 -0700 Subject: [PATCH 16/16] Fix comparison after rebase --- src/librustc/traits/error_reporting.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d5f22afa9afc2..daa4a215a238a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1060,7 +1060,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let restrict_msg = "consider further restricting this bound"; let param_name = self_ty.to_string(); for param in generics.params.iter().filter(|p| { - ¶m_name == p.name.ident().as_str() + ¶m_name == std::convert::AsRef::::as_ref(&p.name.ident().as_str()) }) { if param_name.starts_with("impl ") { // `impl Trait` in argument: