Skip to content

Commit 9b329ed

Browse files
author
Allen Hsu
committed
Support trait bounds with type parameters.
1 parent 2f518f9 commit 9b329ed

4 files changed

+106
-40
lines changed

clippy_lints/src/trait_bounds.rs

+79-39
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use rustc_data_structures::unhash::UnhashMap;
88
use rustc_errors::Applicability;
99
use rustc_hir::def::Res;
1010
use rustc_hir::{
11-
GenericBound, Generics, Item, ItemKind, Node, ParamName, Path, PathSegment, QPath, TraitItem, Ty, TyKind,
12-
WherePredicate,
11+
GenericArg, GenericBound, Generics, Item, ItemKind, Node, ParamName, Path, PathSegment, QPath, TraitItem, Ty,
12+
TyKind, WherePredicate,
1313
};
1414
use rustc_lint::{LateContext, LateLintPass};
1515
use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -289,44 +289,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
289289
}
290290
}
291291

292-
fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
293-
fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
294-
let mut map = FxHashMap::default();
295-
let mut repeated_spans = false;
296-
for bound in bounds.iter().filter_map(get_trait_info_from_bound) {
297-
let (definition, _, span_direct) = bound;
298-
if map.insert(definition, span_direct).is_some() {
299-
repeated_spans = true;
300-
}
301-
}
302-
303-
if_chain! {
304-
if repeated_spans;
305-
if let Some(first_trait) = bounds.get(0);
306-
if let Some(last_trait) = bounds.iter().last();
307-
then {
308-
let all_trait_span = first_trait.span().to(last_trait.span());
309-
310-
let mut traits = map.values()
311-
.filter_map(|span| snippet_opt(cx, *span))
312-
.collect::<Vec<_>>();
313-
traits.sort_unstable();
314-
let traits = traits.join(" + ");
315-
316-
span_lint_and_sugg(
317-
cx,
318-
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
319-
all_trait_span,
320-
msg,
321-
"try",
322-
traits,
323-
Applicability::MachineApplicable
324-
);
325-
}
326-
}
327-
}
292+
#[derive(PartialEq, Eq, Hash, Debug)]
293+
struct ComparableBound(Res, Vec<Res>, Vec<ComparableBound>);
328294

329-
if gen.span.from_expansion() || (gen.params.is_empty() && gen.where_clause.predicates.is_empty()) {
295+
fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
296+
if gen.span.from_expansion() {
330297
return;
331298
}
332299

@@ -355,3 +322,76 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'
355322
None
356323
}
357324
}
325+
326+
fn try_into_comparable_bound(bound: &GenericBound<'_>) -> Option<ComparableBound> {
327+
if let GenericBound::Trait(t, _) = bound {
328+
Some(ComparableBound(
329+
t.trait_ref.path.res,
330+
t.trait_ref
331+
.path
332+
.segments
333+
.iter()
334+
.filter_map(|segment| {
335+
// get trait bound type arguments
336+
Some(segment.args?.args.iter().filter_map(|arg| {
337+
if_chain! {
338+
if let GenericArg::Type(ty) = arg;
339+
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
340+
then { return Some(path.res) }
341+
}
342+
None
343+
}))
344+
})
345+
.flatten()
346+
.collect(),
347+
t.bound_generic_params
348+
.iter()
349+
.flat_map(|param| param.bounds.iter().filter_map(try_into_comparable_bound))
350+
.collect(),
351+
))
352+
} else {
353+
None
354+
}
355+
}
356+
357+
fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
358+
let mut map = FxHashMap::default();
359+
let mut repeated_spans = false;
360+
for bound in bounds.iter().filter_map(|bound| {
361+
if let GenericBound::Trait(t, _) = bound {
362+
Some((try_into_comparable_bound(bound)?, t.span))
363+
} else {
364+
None
365+
}
366+
}) {
367+
let (comparable_bound, span_direct) = bound;
368+
if map.insert(comparable_bound, span_direct).is_some() {
369+
repeated_spans = true;
370+
}
371+
}
372+
373+
if_chain! {
374+
if repeated_spans;
375+
if let Some(first_trait) = bounds.get(0);
376+
if let Some(last_trait) = bounds.iter().last();
377+
then {
378+
let all_trait_span = first_trait.span().to(last_trait.span());
379+
380+
let mut traits = map.values()
381+
.filter_map(|span| snippet_opt(cx, *span))
382+
.collect::<Vec<_>>();
383+
traits.sort_unstable();
384+
let traits = traits.join(" + ");
385+
386+
span_lint_and_sugg(
387+
cx,
388+
REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND,
389+
all_trait_span,
390+
msg,
391+
"try",
392+
traits,
393+
Applicability::MachineApplicable
394+
);
395+
}
396+
}
397+
}

tests/ui/repeated_where_clause_or_trait_bound.fixed

+10
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,14 @@ where
9292

9393
fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
9494

95+
trait GenericTrait<T> {}
96+
97+
fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
98+
unimplemented!();
99+
}
100+
101+
fn bad_generic<T: GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
102+
unimplemented!();
103+
}
104+
95105
fn main() {}

tests/ui/repeated_where_clause_or_trait_bound.rs

+10
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,14 @@ where
9292

9393
fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
9494

95+
trait GenericTrait<T> {}
96+
97+
fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
98+
unimplemented!();
99+
}
100+
101+
fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
102+
unimplemented!();
103+
}
104+
95105
fn main() {}

tests/ui/repeated_where_clause_or_trait_bound.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,11 @@ error: this where clause contains repeated elements
3434
LL | T: Clone + Clone + Clone + Copy,
3535
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
3636

37-
error: aborting due to 5 previous errors
37+
error: this trait bound contains repeated elements
38+
--> $DIR/repeated_where_clause_or_trait_bound.rs:101:19
39+
|
40+
LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u32> + GenericTrait<u64>`
42+
43+
error: aborting due to 6 previous errors
3844

0 commit comments

Comments
 (0)