From 92616c0aaac07bf589a2d40502dd5dec804e8318 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 27 Nov 2023 00:43:47 +0100 Subject: [PATCH] [`implied_bounds_in_impls`]: avoid linting on overlapping associated types --- clippy_lints/src/implied_bounds_in_impls.rs | 9 +++++ tests/ui/implied_bounds_in_impls.fixed | 29 ++++++++++++++++ tests/ui/implied_bounds_in_impls.rs | 29 ++++++++++++++++ tests/ui/implied_bounds_in_impls.stderr | 38 ++++++++++++++++++++- 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index cc6ece45fcdba..174db30a7cd49 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -317,6 +317,15 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { && let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings) && let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id() && let Some(bound) = find_bound_in_supertraits(cx, def_id, implied_args, &supertraits) + // If the implied bound has a type binding that also exists in the implied-by trait, + // then we shouldn't lint. See #11880 for an example. + && let assocs = cx.tcx.associated_items(bound.trait_def_id) + && !implied_bindings.iter().any(|binding| { + assocs + .filter_by_name_unhygienic(binding.ident.name) + .next() + .is_some_and(|assoc| assoc.kind == ty::AssocKind::Type) + }) { emit_lint(cx, poly_trait, opaque_ty, index, implied_bindings, bound); } diff --git a/tests/ui/implied_bounds_in_impls.fixed b/tests/ui/implied_bounds_in_impls.fixed index fa117aaddcd60..18f29e900c15f 100644 --- a/tests/ui/implied_bounds_in_impls.fixed +++ b/tests/ui/implied_bounds_in_impls.fixed @@ -121,4 +121,33 @@ mod issue11435 { fn f3() -> impl Trait4 {} } +fn issue11880() { + trait X { + type T; + type U; + } + trait Y: X { + type T; + type V; + } + impl X for () { + type T = i32; + type U = String; + } + impl Y for () { + type T = u32; + type V = Vec; + } + + // Can't constrain `X::T` through `Y` + fn f() -> impl X + Y {} + fn f2() -> impl X + Y {} + + // X::T is never constrained in the first place, so it can be omitted + // and left unconstrained + fn f3() -> impl Y {} + fn f4() -> impl Y {} + fn f5() -> impl Y {} +} + fn main() {} diff --git a/tests/ui/implied_bounds_in_impls.rs b/tests/ui/implied_bounds_in_impls.rs index c96aac151a7d0..b7951e7dfba8b 100644 --- a/tests/ui/implied_bounds_in_impls.rs +++ b/tests/ui/implied_bounds_in_impls.rs @@ -121,4 +121,33 @@ mod issue11435 { fn f3() -> impl Trait3 + Trait4 {} } +fn issue11880() { + trait X { + type T; + type U; + } + trait Y: X { + type T; + type V; + } + impl X for () { + type T = i32; + type U = String; + } + impl Y for () { + type T = u32; + type V = Vec; + } + + // Can't constrain `X::T` through `Y` + fn f() -> impl X + Y {} + fn f2() -> impl X + Y {} + + // X::T is never constrained in the first place, so it can be omitted + // and left unconstrained + fn f3() -> impl X + Y {} + fn f4() -> impl X + Y {} + fn f5() -> impl X + Y {} +} + fn main() {} diff --git a/tests/ui/implied_bounds_in_impls.stderr b/tests/ui/implied_bounds_in_impls.stderr index fb44f2aba1744..3b09e4582e30d 100644 --- a/tests/ui/implied_bounds_in_impls.stderr +++ b/tests/ui/implied_bounds_in_impls.stderr @@ -192,5 +192,41 @@ LL - fn f3() -> impl Trait3 + Trait4 impl Trait4 {} | -error: aborting due to 16 previous errors +error: this bound is already specified as the supertrait of `Y` + --> $DIR/implied_bounds_in_impls.rs:148:21 + | +LL | fn f3() -> impl X + Y {} + | ^ + | +help: try removing this bound + | +LL - fn f3() -> impl X + Y {} +LL + fn f3() -> impl Y {} + | + +error: this bound is already specified as the supertrait of `Y` + --> $DIR/implied_bounds_in_impls.rs:149:21 + | +LL | fn f4() -> impl X + Y {} + | ^ + | +help: try removing this bound + | +LL - fn f4() -> impl X + Y {} +LL + fn f4() -> impl Y {} + | + +error: this bound is already specified as the supertrait of `Y` + --> $DIR/implied_bounds_in_impls.rs:150:21 + | +LL | fn f5() -> impl X + Y {} + | ^^^^^^^^^^^^^ + | +help: try removing this bound + | +LL - fn f5() -> impl X + Y {} +LL + fn f5() -> impl Y {} + | + +error: aborting due to 19 previous errors