Skip to content

Commit 171d082

Browse files
aldhsuAllen Hsu
authored and
Allen Hsu
committed
Compare where predicates to trait bounds.
- only compare where predicates to trait bounds when generating where clause specific message to fix #9151 - use comparable_trait_ref to account for trait bound generics to fix #8757
1 parent d72e5f2 commit 171d082

File tree

2 files changed

+50
-71
lines changed

2 files changed

+50
-71
lines changed

clippy_lints/src/trait_bounds.rs

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use clippy_utils::{SpanlessEq, SpanlessHash};
44
use core::hash::{Hash, Hasher};
55
use if_chain::if_chain;
66
use itertools::Itertools;
7-
use rustc_data_structures::fx::FxHashMap;
7+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
88
use rustc_data_structures::unhash::UnhashMap;
99
use rustc_errors::Applicability;
1010
use rustc_hir::def::Res;
@@ -238,31 +238,58 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
238238
return;
239239
}
240240

241-
let mut map = FxHashMap::<_, Vec<_>>::default();
242-
for predicate in gen.predicates {
241+
// Explanation:
242+
// fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
243+
// where T: Clone + Default, { unimplemented!(); }
244+
// ^^^^^^^^^^^^^^^^^^
245+
// |
246+
// collects each of these where clauses into a set keyed by generic name and comparable trait
247+
// eg. (T, Clone)
248+
let where_predicates = gen
249+
.predicates
250+
.iter()
251+
.filter_map(|pred| {
252+
if_chain! {
253+
if pred.in_where_clause();
254+
if let WherePredicate::BoundPredicate(bound_predicate) = pred;
255+
if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind;
256+
then {
257+
return Some(bound_predicate.bounds.iter().filter_map(|t| {
258+
Some((path.res, into_comparable_trait_ref(t.trait_ref()?)))
259+
}))
260+
}
261+
}
262+
None
263+
})
264+
.flatten()
265+
.collect::<FxHashSet<_>>();
266+
267+
// Explanation:
268+
// fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z) ...
269+
// ^^^^^^^^^^^^^^^^^^ ^^^^^^^
270+
// |
271+
// compare trait bounds keyed by generic name and comparable trait to collected where
272+
// predicates eg. (T, Clone)
273+
for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) {
243274
if_chain! {
244-
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
275+
if let WherePredicate::BoundPredicate(bound_predicate) = predicate;
245276
if bound_predicate.origin != PredicateOrigin::ImplTrait;
246277
if !bound_predicate.span.from_expansion();
247-
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
248-
if let Some(segment) = segments.first();
278+
if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind;
249279
then {
250-
for (res_where, _, span_where) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
251-
let trait_resolutions_direct = map.entry(segment.ident).or_default();
252-
if let Some((_, span_direct)) = trait_resolutions_direct
253-
.iter()
254-
.find(|(res_direct, _)| *res_direct == res_where) {
255-
span_lint_and_help(
256-
cx,
257-
TRAIT_DUPLICATION_IN_BOUNDS,
258-
*span_direct,
259-
"this trait bound is already specified in the where clause",
260-
None,
261-
"consider removing this trait bound",
262-
);
263-
}
264-
else {
265-
trait_resolutions_direct.push((res_where, span_where));
280+
for t in bound_predicate.bounds {
281+
if let Some(trait_ref) = t.trait_ref() {
282+
let key = (path.res, into_comparable_trait_ref(trait_ref));
283+
if where_predicates.contains(&key) {
284+
span_lint_and_help(
285+
cx,
286+
TRAIT_DUPLICATION_IN_BOUNDS,
287+
t.span(),
288+
"this trait bound is already specified in the where clause",
289+
None,
290+
"consider removing this trait bound",
291+
);
292+
}
266293
}
267294
}
268295
}

tests/ui/trait_duplication_in_bounds.stderr

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -67,28 +67,12 @@ LL | Self: Iterator<Item = Foo>,
6767
|
6868
= help: consider removing this trait bound
6969

70-
error: this trait bound is already specified in the where clause
71-
--> $DIR/trait_duplication_in_bounds.rs:103:19
72-
|
73-
LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
74-
| ^^^^^
75-
|
76-
= help: consider removing this trait bound
77-
7870
error: these bounds contain repeated elements
7971
--> $DIR/trait_duplication_in_bounds.rs:103:19
8072
|
8173
LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
8274
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
8375

84-
error: this trait bound is already specified in the where clause
85-
--> $DIR/trait_duplication_in_bounds.rs:109:12
86-
|
87-
LL | T: Clone + Clone + Clone + Copy,
88-
| ^^^^^
89-
|
90-
= help: consider removing this trait bound
91-
9276
error: these where clauses contain repeated elements
9377
--> $DIR/trait_duplication_in_bounds.rs:109:12
9478
|
@@ -107,14 +91,6 @@ error: these where clauses contain repeated elements
10791
LL | Self: Clone + Clone + Clone;
10892
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
10993

110-
error: this trait bound is already specified in the where clause
111-
--> $DIR/trait_duplication_in_bounds.rs:158:28
112-
|
113-
LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
114-
| ^^^^^
115-
|
116-
= help: consider removing this trait bound
117-
11894
error: these bounds contain repeated elements
11995
--> $DIR/trait_duplication_in_bounds.rs:158:28
12096
|
@@ -127,41 +103,17 @@ error: these where clauses contain repeated elements
127103
LL | T: Clone + Clone + Clone + Copy,
128104
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
129105

130-
error: this trait bound is already specified in the where clause
131-
--> $DIR/trait_duplication_in_bounds.rs:195:24
132-
|
133-
LL | fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
134-
| ^^^^^^^^^^^^^^^^^
135-
|
136-
= help: consider removing this trait bound
137-
138-
error: this trait bound is already specified in the where clause
139-
--> $DIR/trait_duplication_in_bounds.rs:199:23
140-
|
141-
LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
142-
| ^^^^^^^^^^^^^^^^^
143-
|
144-
= help: consider removing this trait bound
145-
146106
error: these bounds contain repeated elements
147107
--> $DIR/trait_duplication_in_bounds.rs:199:23
148108
|
149109
LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
150110
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u32> + GenericTrait<u64>`
151111

152-
error: this trait bound is already specified in the where clause
153-
--> $DIR/trait_duplication_in_bounds.rs:207:26
154-
|
155-
LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
156-
| ^^^^^^^^^^^^^^^^^
157-
|
158-
= help: consider removing this trait bound
159-
160112
error: these bounds contain repeated elements
161113
--> $DIR/trait_duplication_in_bounds.rs:207:26
162114
|
163115
LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
164116
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + foo::Clone`
165117

166-
error: aborting due to 22 previous errors
118+
error: aborting due to 16 previous errors
167119

0 commit comments

Comments
 (0)