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] 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 338fabca3891..f49fde04e844 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 c76b6bc9c185..08174d8d8d53 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 067b10b873ab..05d3de80d844 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