From f6e6d2a035d9e86e7053847aa60a99940f41064c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 12 Jan 2023 19:53:01 +0000 Subject: [PATCH 1/4] Elaborate unmet obligations in E0599 for more context --- compiler/rustc_hir_typeck/src/method/probe.rs | 28 ++++++++++++++---- tests/ui/derives/issue-91550.stderr | 29 ++++++++++++++++--- .../ui/missing-trait-bounds/issue-35677.fixed | 2 +- .../missing-trait-bounds/issue-35677.stderr | 6 ++-- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index dd827777df94e..15f6e11717768 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1587,11 +1587,29 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let o = self.resolve_vars_if_possible(o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; - possibly_unsatisfied_predicates.push(( - o.predicate, - None, - Some(o.cause), - )); + let parent_o = o.clone(); + let implied_obligations = + traits::elaborate_obligations(self.tcx, vec![o]); + for o in implied_obligations { + let parent = if o == parent_o { + None + } else { + if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id()) + == self.tcx.lang_items().sized_trait() + { + // We don't care to talk about implicit `Sized` bounds. + continue; + } + Some(parent_o.predicate) + }; + if !self.predicate_may_hold(&o) { + possibly_unsatisfied_predicates.push(( + o.predicate, + parent, + Some(o.cause), + )); + } + } } } } diff --git a/tests/ui/derives/issue-91550.stderr b/tests/ui/derives/issue-91550.stderr index bf0bb3fbdf8f7..381d860a9c36d 100644 --- a/tests/ui/derives/issue-91550.stderr +++ b/tests/ui/derives/issue-91550.stderr @@ -6,12 +6,15 @@ LL | struct Value(u32); | | | doesn't satisfy `Value: Eq` | doesn't satisfy `Value: Hash` + | doesn't satisfy `Value: PartialEq` ... LL | hs.insert(Value(0)); | ^^^^^^ | = note: the following trait bounds were not satisfied: `Value: Eq` + `Value: PartialEq` + which is required by `Value: Eq` `Value: Hash` help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]` | @@ -22,7 +25,10 @@ error[E0599]: the method `use_eq` exists for struct `Object`, but its --> $DIR/issue-91550.rs:26:9 | LL | pub struct NoDerives; - | -------------------- doesn't satisfy `NoDerives: Eq` + | -------------------- + | | + | doesn't satisfy `NoDerives: Eq` + | doesn't satisfy `NoDerives: PartialEq` LL | LL | struct Object(T); | ---------------- method `use_eq` not found for this struct @@ -30,7 +36,9 @@ LL | struct Object(T); LL | foo.use_eq(); | ^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds | -note: trait bound `NoDerives: Eq` was not satisfied +note: the following trait bounds were not satisfied: + `NoDerives: Eq` + `NoDerives: PartialEq` --> $DIR/issue-91550.rs:15:9 | LL | impl Object { @@ -46,7 +54,12 @@ error[E0599]: the method `use_ord` exists for struct `Object`, but it --> $DIR/issue-91550.rs:27:9 | LL | pub struct NoDerives; - | -------------------- doesn't satisfy `NoDerives: Ord` + | -------------------- + | | + | doesn't satisfy `NoDerives: Eq` + | doesn't satisfy `NoDerives: Ord` + | doesn't satisfy `NoDerives: PartialEq` + | doesn't satisfy `NoDerives: PartialOrd` LL | LL | struct Object(T); | ---------------- method `use_ord` not found for this struct @@ -54,7 +67,11 @@ LL | struct Object(T); LL | foo.use_ord(); | ^^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds | -note: trait bound `NoDerives: Ord` was not satisfied +note: the following trait bounds were not satisfied: + `NoDerives: Eq` + `NoDerives: Ord` + `NoDerives: PartialEq` + `NoDerives: PartialOrd` --> $DIR/issue-91550.rs:18:9 | LL | impl Object { @@ -72,7 +89,9 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object(T); @@ -82,7 +101,9 @@ LL | foo.use_ord_and_partial_ord(); | ^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds | note: the following trait bounds were not satisfied: + `NoDerives: Eq` `NoDerives: Ord` + `NoDerives: PartialEq` `NoDerives: PartialOrd` --> $DIR/issue-91550.rs:21:9 | diff --git a/tests/ui/missing-trait-bounds/issue-35677.fixed b/tests/ui/missing-trait-bounds/issue-35677.fixed index 08174d8d8d53a..c76b6bc9c1851 100644 --- a/tests/ui/missing-trait-bounds/issue-35677.fixed +++ b/tests/ui/missing-trait-bounds/issue-35677.fixed @@ -3,7 +3,7 @@ use std::collections::HashSet; use std::hash::Hash; -fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash { +fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash, T: PartialEq { this.is_subset(other) //~^ ERROR the method } diff --git a/tests/ui/missing-trait-bounds/issue-35677.stderr b/tests/ui/missing-trait-bounds/issue-35677.stderr index a2201b946a6f0..067b10b873abf 100644 --- a/tests/ui/missing-trait-bounds/issue-35677.stderr +++ b/tests/ui/missing-trait-bounds/issue-35677.stderr @@ -6,11 +6,13 @@ LL | this.is_subset(other) | = note: the following trait bounds were not satisfied: `T: Eq` + `T: PartialEq` + which is required by `T: Eq` `T: Hash` help: consider restricting the type parameters to satisfy the trait bounds | -LL | fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash { - | ++++++++++++++++++++ +LL | fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash, T: PartialEq { + | ++++++++++++++++++++++++++++++++++ error: aborting due to previous error From 3d6b09e53e0b1d5920fe3c6106f676b7b95f4a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 12 Jan 2023 21:32:06 +0000 Subject: [PATCH 2/4] Keep obligation chain when elaborating obligations --- .../rustc_hir_typeck/src/method/suggest.rs | 15 +++++++++- compiler/rustc_infer/src/traits/util.rs | 18 ++++++++++-- .../issue-43784-associated-type.stderr | 5 ++++ tests/ui/derives/issue-91550.stderr | 29 ++++++++++++------- .../issue-74824.stderr | 1 + tests/ui/traits/issue-43784-supertrait.stderr | 5 ++++ 6 files changed, 59 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8166eb8299041..338fabca38919 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -692,7 +692,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "auto trait is invoked with no method error, but no error reported?", ); } - Some(_) => unreachable!(), + Some(Node::Item(hir::Item { + ident, kind: hir::ItemKind::Trait(..), .. + })) => { + skip_list.insert(p); + let entry = spanned_predicates.entry(ident.span); + let entry = entry.or_insert_with(|| { + (FxHashSet::default(), FxHashSet::default(), Vec::new()) + }); + entry.0.insert(cause.span); + entry.1.insert((ident.span, "")); + entry.1.insert((cause.span, "unsatisfied trait bound introduced here")); + entry.2.push(p); + } + Some(node) => unreachable!("encountered `{node:?}`"), None => (), } } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 8f0bd3a9abe5e..1817bbf922854 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,7 +1,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; -use crate::traits::{Obligation, ObligationCause, PredicateObligation}; +use crate::traits::{self, Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_middle::ty::{self, ToPredicate, TyCtxt}; use rustc_span::symbol::Ident; @@ -145,16 +145,28 @@ impl<'tcx> Elaborator<'tcx> { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); - let obligations = predicates.predicates.iter().map(|&(mut pred, _)| { + let obligations = predicates.predicates.iter().map(|&(mut pred, span)| { // when parent predicate is non-const, elaborate it to non-const predicates. if data.constness == ty::BoundConstness::NotConst { pred = pred.without_const(tcx); } + let cause = obligation.cause.clone().derived_cause( + bound_predicate.rebind(data), + |derived| { + traits::ImplDerivedObligation(Box::new( + traits::ImplDerivedObligationCause { + derived, + impl_def_id: data.def_id(), + span, + }, + )) + }, + ); predicate_obligation( pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)), obligation.param_env, - obligation.cause.clone(), + cause, ) }); debug!(?data, ?obligations, "super_predicates"); diff --git a/tests/ui/associated-types/issue-43784-associated-type.stderr b/tests/ui/associated-types/issue-43784-associated-type.stderr index f1677b822b4c9..50fa7d1ac4d43 100644 --- a/tests/ui/associated-types/issue-43784-associated-type.stderr +++ b/tests/ui/associated-types/issue-43784-associated-type.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied LL | type Assoc = T; | ^ the trait `Copy` is not implemented for `T` | +note: required for `::Assoc` to implement `Partial` + --> $DIR/issue-43784-associated-type.rs:1:11 + | +LL | pub trait Partial: Copy { + | ^^^^^^^ note: required by a bound in `Complete::Assoc` --> $DIR/issue-43784-associated-type.rs:5:17 | diff --git a/tests/ui/derives/issue-91550.stderr b/tests/ui/derives/issue-91550.stderr index 381d860a9c36d..af03f0e5e5f43 100644 --- a/tests/ui/derives/issue-91550.stderr +++ b/tests/ui/derives/issue-91550.stderr @@ -36,15 +36,16 @@ LL | struct Object(T); LL | foo.use_eq(); | ^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds | -note: the following trait bounds were not satisfied: - `NoDerives: Eq` - `NoDerives: PartialEq` +note: trait bound `NoDerives: Eq` was not satisfied --> $DIR/issue-91550.rs:15:9 | LL | impl Object { | ^^ --------- | | | unsatisfied trait bound introduced here + = note: the following trait bounds were not satisfied: + `NoDerives: PartialEq` + which is required by `NoDerives: Eq` help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]` | LL | #[derive(Eq, PartialEq)] @@ -67,17 +68,20 @@ LL | struct Object(T); LL | foo.use_ord(); | ^^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds | -note: the following trait bounds were not satisfied: - `NoDerives: Eq` - `NoDerives: Ord` - `NoDerives: PartialEq` - `NoDerives: PartialOrd` +note: trait bound `NoDerives: Ord` was not satisfied --> $DIR/issue-91550.rs:18:9 | LL | impl Object { | ^^^ --------- | | | unsatisfied trait bound introduced here + = note: the following trait bounds were not satisfied: + `NoDerives: PartialOrd` + which is required by `NoDerives: Ord` + `NoDerives: PartialEq` + which is required by `NoDerives: Ord` + `NoDerives: Eq` + which is required by `NoDerives: Ord` help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] @@ -101,9 +105,7 @@ LL | foo.use_ord_and_partial_ord(); | ^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds | note: the following trait bounds were not satisfied: - `NoDerives: Eq` `NoDerives: Ord` - `NoDerives: PartialEq` `NoDerives: PartialOrd` --> $DIR/issue-91550.rs:21:9 | @@ -112,6 +114,13 @@ LL | impl Object { | | | | | unsatisfied trait bound introduced here | unsatisfied trait bound introduced here + = note: the following trait bounds were not satisfied: + `NoDerives: PartialEq` + which is required by `NoDerives: Ord` + `NoDerives: Eq` + which is required by `NoDerives: Ord` + `NoDerives: PartialEq` + which is required by `NoDerives: PartialOrd` help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] diff --git a/tests/ui/generic-associated-types/issue-74824.stderr b/tests/ui/generic-associated-types/issue-74824.stderr index 623adb1c2ad1e..e5638d90ee8e7 100644 --- a/tests/ui/generic-associated-types/issue-74824.stderr +++ b/tests/ui/generic-associated-types/issue-74824.stderr @@ -17,6 +17,7 @@ LL | type Copy: Copy = Box; | ^^^^^^ the trait `Clone` is not implemented for `T` | = note: required for `Box` to implement `Clone` + = note: required for `::Copy` to implement `Copy` note: required by a bound in `UnsafeCopy::Copy` --> $DIR/issue-74824.rs:6:19 | diff --git a/tests/ui/traits/issue-43784-supertrait.stderr b/tests/ui/traits/issue-43784-supertrait.stderr index 4fe12731475b4..6b5b721384cbb 100644 --- a/tests/ui/traits/issue-43784-supertrait.stderr +++ b/tests/ui/traits/issue-43784-supertrait.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied LL | impl Complete for T {} | ^ the trait `Copy` is not implemented for `T` | +note: required for `T` to implement `Partial` + --> $DIR/issue-43784-supertrait.rs:1:11 + | +LL | pub trait Partial: Copy { + | ^^^^^^^ note: required by a bound in `Complete` --> $DIR/issue-43784-supertrait.rs:4:21 | From 81ba427a7b15d614a74812ef3fd1467c85d4768d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 12 Jan 2023 21:48:07 +0000 Subject: [PATCH 3/4] Add tests --- tests/ui/traits/track-obligations.rs | 88 ++++++++++++++++++++++++ tests/ui/traits/track-obligations.stderr | 76 ++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 tests/ui/traits/track-obligations.rs create mode 100644 tests/ui/traits/track-obligations.stderr diff --git a/tests/ui/traits/track-obligations.rs b/tests/ui/traits/track-obligations.rs new file mode 100644 index 0000000000000..77e753c13f739 --- /dev/null +++ b/tests/ui/traits/track-obligations.rs @@ -0,0 +1,88 @@ +// These are simplifications of the tower traits by the same name: + +pub trait Service { + type Response; +} + +pub trait Layer { + type Service; +} + +// Any type will do here: + +pub struct Req; +pub struct Res; + +// This is encoding a trait alias. + +pub trait ParticularService: + Service { +} + +impl ParticularService for T +where + T: Service, +{ +} + +// This is also a trait alias. +// The weird = bound is there so that users of the trait do not +// need to repeat the bounds. See https://github.com/rust-lang/rust/issues/20671 +// for context, and in particular the workaround in: +// https://github.com/rust-lang/rust/issues/20671#issuecomment-529752828 + +pub trait ParticularServiceLayer: + Layer>::Service> +{ + type Service: ParticularService; +} + +impl ParticularServiceLayer for T +where + T: Layer, + T::Service: ParticularService, +{ + type Service = T::Service; +} + +// These are types that implement the traits that the trait aliases refer to. +// They should also implement the alias traits due to the blanket impls. + +struct ALayer(C); +impl Layer for ALayer { + type Service = AService; +} + +struct AService; +impl Service for AService { + // However, AService does _not_ meet the blanket implementation, + // since its Response type is bool, not Res as it should be. + type Response = bool; +} + +// This is a wrapper type around ALayer that uses the trait alias +// as a way to communicate the requirements of the provided types. +struct Client(C); + +// The method and the free-standing function below both have the same bounds. + +impl Client +where + ALayer: ParticularServiceLayer, +{ + fn check(&self) {} +} + +fn check(_: C) where ALayer: ParticularServiceLayer {} + +// But, they give very different error messages. + +fn main() { + // This gives a very poor error message that does nothing to point the user + // at the underlying cause of why the types involved do not meet the bounds. + Client(()).check(); //~ ERROR E0599 + + // This gives a good(ish) error message that points the user at _why_ the + // bound isn't met, and thus how they might fix it. + check(()); //~ ERROR E0271 +} diff --git a/tests/ui/traits/track-obligations.stderr b/tests/ui/traits/track-obligations.stderr new file mode 100644 index 0000000000000..89477475970f4 --- /dev/null +++ b/tests/ui/traits/track-obligations.stderr @@ -0,0 +1,76 @@ +error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied + --> $DIR/track-obligations.rs:83:16 + | +LL | struct ALayer(C); + | ---------------- + | | + | doesn't satisfy `<_ as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` + | doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>` +... +LL | struct Client(C); + | ---------------- method `check` not found for this struct +... +LL | Client(()).check(); + | ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds + | +note: trait bound ` as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` was not satisfied + --> $DIR/track-obligations.rs:35:14 + | +LL | pub trait ParticularServiceLayer: + | ---------------------- +LL | Layer>::Service> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here +note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied + --> $DIR/track-obligations.rs:71:16 + | +LL | impl Client + | --------- +LL | where +LL | ALayer: ParticularServiceLayer, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here +note: the trait `ParticularServiceLayer` must be implemented + --> $DIR/track-obligations.rs:34:1 + | +LL | / pub trait ParticularServiceLayer: +LL | | Layer>::Service> + | |____________________________________________________________________^ + +error[E0271]: type mismatch resolving `>::Response == Res` + --> $DIR/track-obligations.rs:87:11 + | +LL | check(()); + | ----- ^^ type mismatch resolving `>::Response == Res` + | | + | required by a bound introduced by this call + | +note: expected this to be `Res` + --> $DIR/track-obligations.rs:60:21 + | +LL | type Response = bool; + | ^^^^ +note: required for `AService` to implement `ParticularService` + --> $DIR/track-obligations.rs:22:9 + | +LL | impl ParticularService for T + | ^^^^^^^^^^^^^^^^^ ^ +LL | where +LL | T: Service, + | -------------- unsatisfied trait bound introduced here +note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>` + --> $DIR/track-obligations.rs:40:12 + | +LL | impl ParticularServiceLayer for T + | ^^^^^^^^^^^^^^^^^^^^^^^^^ ^ +... +LL | T::Service: ParticularService, + | ----------------- unsatisfied trait bound introduced here +note: required by a bound in `check` + --> $DIR/track-obligations.rs:76:36 + | +LL | fn check(_: C) where ALayer: ParticularServiceLayer {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0271, E0599. +For more information about an error, try `rustc --explain E0271`. From 22a0e4fa6e08acf2de50ed87cfb909092ab0459d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 13 Jan 2023 20:50:34 +0000 Subject: [PATCH 4/4] Do not incorrectly suggest restricting implied bounds When we have already suggested bounds that imply the about to be suggested bound, skip them. --- .../rustc_hir_typeck/src/method/suggest.rs | 48 ++++++++++++++----- .../ui/missing-trait-bounds/issue-35677.fixed | 2 +- .../missing-trait-bounds/issue-35677.stderr | 4 +- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 338fabca38919..f49fde04e8444 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -505,19 +505,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => None, }; - if let Some(hir::Node::Item(hir::Item { kind, .. })) = node { - if let Some(g) = kind.generics() { - let key = ( - g.tail_span_for_predicate_suggestion(), - g.add_where_or_trailing_comma(), - ); - type_params - .entry(key) - .or_insert_with(FxHashSet::default) - .insert(obligation.to_owned()); - } + if let Some(hir::Node::Item(hir::Item { kind, .. })) = node + && let Some(g) = kind.generics() + { + let key = ( + g.tail_span_for_predicate_suggestion(), + g.add_where_or_trailing_comma(), + ); + type_params + .entry(key) + .or_insert_with(FxHashSet::default) + .insert(obligation.to_owned()); + return true; } } + false }; let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { let msg = format!( @@ -732,19 +734,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_bounds = true; } + let mut suggested_bounds = FxHashSet::default(); // The requirements that didn't have an `impl` span to show. let mut bound_list = unsatisfied_predicates .iter() .filter_map(|(pred, parent_pred, _cause)| { + let mut suggested = false; format_pred(*pred).map(|(p, self_ty)| { - collect_type_param_suggestions(self_ty, *pred, &p); + if let Some(parent) = parent_pred && suggested_bounds.contains(parent) { + // We don't suggest `PartialEq` when we already suggest `Eq`. + } else if !suggested_bounds.contains(pred) { + if collect_type_param_suggestions(self_ty, *pred, &p) { + suggested = true; + suggested_bounds.insert(pred); + } + } ( match parent_pred { None => format!("`{}`", &p), Some(parent_pred) => match format_pred(*parent_pred) { None => format!("`{}`", &p), Some((parent_p, _)) => { - collect_type_param_suggestions(self_ty, *parent_pred, &p); + if !suggested + && !suggested_bounds.contains(pred) + && !suggested_bounds.contains(parent_pred) + { + if collect_type_param_suggestions( + self_ty, + *parent_pred, + &p, + ) { + suggested_bounds.insert(pred); + } + } format!("`{}`\nwhich is required by `{}`", p, parent_p) } }, diff --git a/tests/ui/missing-trait-bounds/issue-35677.fixed b/tests/ui/missing-trait-bounds/issue-35677.fixed index c76b6bc9c1851..08174d8d8d53a 100644 --- a/tests/ui/missing-trait-bounds/issue-35677.fixed +++ b/tests/ui/missing-trait-bounds/issue-35677.fixed @@ -3,7 +3,7 @@ use std::collections::HashSet; use std::hash::Hash; -fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash, T: PartialEq { +fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash { this.is_subset(other) //~^ ERROR the method } diff --git a/tests/ui/missing-trait-bounds/issue-35677.stderr b/tests/ui/missing-trait-bounds/issue-35677.stderr index 067b10b873abf..05d3de80d8449 100644 --- a/tests/ui/missing-trait-bounds/issue-35677.stderr +++ b/tests/ui/missing-trait-bounds/issue-35677.stderr @@ -11,8 +11,8 @@ LL | this.is_subset(other) `T: Hash` help: consider restricting the type parameters to satisfy the trait bounds | -LL | fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash, T: PartialEq { - | ++++++++++++++++++++++++++++++++++ +LL | fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash { + | ++++++++++++++++++++ error: aborting due to previous error