about summary refs log tree commit diff
diff options
context:
space:
mode:
authorllogiq <bogusandre@gmail.com>2024-11-25 20:24:39 +0000
committerGitHub <noreply@github.com>2024-11-25 20:24:39 +0000
commit3d881e1e595dae6d5616bfd41da756967f0ae6c3 (patch)
tree4061150ceb8998e487e6cd13f78b332c7923758d
parentd070402440a5a92f427a981784b39eb460e5f292 (diff)
parent9fd8e99d91f7029016b9097d1311c1045f35667f (diff)
downloadrust-3d881e1e595dae6d5616bfd41da756967f0ae6c3.tar.gz
rust-3d881e1e595dae6d5616bfd41da756967f0ae6c3.zip
Prevent ICE in case of a bound constraint on generic argument (#13722)
Fix #13706

changelog: [`trait_duplication_in_bounds`]: fix ICE on duplicate type or
constant bound
-rw-r--r--clippy_utils/src/hir_utils.rs11
-rw-r--r--tests/ui/trait_duplication_in_bounds.fixed17
-rw-r--r--tests/ui/trait_duplication_in_bounds.rs17
3 files changed, 38 insertions, 7 deletions
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index c73ab4bfa68..7bc70836651 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -603,11 +603,7 @@ impl HirEqInterExpr<'_, '_, '_> {
     }
 
     fn eq_assoc_type_binding(&mut self, left: &AssocItemConstraint<'_>, right: &AssocItemConstraint<'_>) -> bool {
-        left.ident.name == right.ident.name
-            && self.eq_ty(
-                left.ty().expect("expected assoc type binding"),
-                right.ty().expect("expected assoc type binding"),
-            )
+        left.ident.name == right.ident.name && both_some_and(left.ty(), right.ty(), |l, r| self.eq_ty(l, r))
     }
 
     fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool {
@@ -727,6 +723,11 @@ pub fn both<X>(l: Option<&X>, r: Option<&X>, mut eq_fn: impl FnMut(&X, &X) -> bo
         .map_or_else(|| r.is_none(), |x| r.as_ref().is_some_and(|y| eq_fn(x, y)))
 }
 
+/// Checks if the two `Option`s are both `Some` and pass the predicate function.
+pub fn both_some_and<X, Y>(l: Option<X>, r: Option<Y>, mut pred: impl FnMut(X, Y) -> bool) -> bool {
+    l.is_some_and(|l| r.is_some_and(|r| pred(l, r)))
+}
+
 /// Checks if two slices are equal as per `eq_fn`.
 pub fn over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
     left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed
index 779431303ae..e57c79553c3 100644
--- a/tests/ui/trait_duplication_in_bounds.fixed
+++ b/tests/ui/trait_duplication_in_bounds.fixed
@@ -1,6 +1,6 @@
 #![deny(clippy::trait_duplication_in_bounds)]
 #![allow(unused)]
-#![feature(const_trait_impl)]
+#![feature(associated_const_equality, const_trait_impl)]
 
 use std::any::Any;
 
@@ -179,3 +179,18 @@ fn main() {
     let _x: fn(_) = f::<()>;
     let _x: fn(_) = f::<i32>;
 }
+
+// #13706
+fn assoc_tys_bounds<T>()
+where
+    T: Iterator<Item: Clone> + Iterator<Item: Clone>,
+{
+}
+trait AssocConstTrait {
+    const ASSOC: usize;
+}
+fn assoc_const_args<T>()
+where
+    T: AssocConstTrait<ASSOC = 0> + AssocConstTrait<ASSOC = 0>,
+{
+}
diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs
index 3e974dc0a8f..ee84d3c3011 100644
--- a/tests/ui/trait_duplication_in_bounds.rs
+++ b/tests/ui/trait_duplication_in_bounds.rs
@@ -1,6 +1,6 @@
 #![deny(clippy::trait_duplication_in_bounds)]
 #![allow(unused)]
-#![feature(const_trait_impl)]
+#![feature(associated_const_equality, const_trait_impl)]
 
 use std::any::Any;
 
@@ -179,3 +179,18 @@ fn main() {
     let _x: fn(_) = f::<()>;
     let _x: fn(_) = f::<i32>;
 }
+
+// #13706
+fn assoc_tys_bounds<T>()
+where
+    T: Iterator<Item: Clone> + Iterator<Item: Clone>,
+{
+}
+trait AssocConstTrait {
+    const ASSOC: usize;
+}
+fn assoc_const_args<T>()
+where
+    T: AssocConstTrait<ASSOC = 0> + AssocConstTrait<ASSOC = 0>,
+{
+}