//@no-rustfix #![warn(clippy::unconditional_recursion)] #![allow( clippy::partialeq_ne_impl, clippy::default_constructed_unit_structs, clippy::only_used_in_recursion )] enum Foo { A, B, } impl PartialEq for Foo { fn ne(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing self != other } fn eq(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing self == other } } enum Foo2 { A, B, } impl PartialEq for Foo2 { fn ne(&self, other: &Self) -> bool { self != &Foo2::B // no error here } fn eq(&self, other: &Self) -> bool { self == &Foo2::B // no error here } } enum Foo3 { A, B, } impl PartialEq for Foo3 { fn ne(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing self.ne(other) } fn eq(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing self.eq(other) } } enum Foo4 { A, B, } impl PartialEq for Foo4 { fn ne(&self, other: &Self) -> bool { self.eq(other) // no error } fn eq(&self, other: &Self) -> bool { self.ne(other) // no error } } enum Foo5 { A, B, } impl Foo5 { fn a(&self) -> bool { true } } impl PartialEq for Foo5 { fn ne(&self, other: &Self) -> bool { self.a() // no error } fn eq(&self, other: &Self) -> bool { self.a() // no error } } struct S; // Check the order doesn't matter. impl PartialEq for S { fn ne(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing other != self } fn eq(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing other == self } } struct S2; // Check that if the same element is compared, it's also triggering the lint. impl PartialEq for S2 { fn ne(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing other != other } fn eq(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing other == other } } struct S3; impl PartialEq for S3 { fn ne(&self, _other: &Self) -> bool { //~^ ERROR: function cannot return without recursing self != self } fn eq(&self, _other: &Self) -> bool { //~^ ERROR: function cannot return without recursing self == self } } // There should be no warning here! #[derive(PartialEq)] enum E { A, B, } #[derive(PartialEq)] struct Bar(T); struct S4; impl PartialEq for S4 { fn eq(&self, other: &Self) -> bool { // No warning here. Bar(self) == Bar(other) } } macro_rules! impl_partial_eq { ($ty:ident) => { impl PartialEq for $ty { fn eq(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing self == other } } }; } struct S5; impl_partial_eq!(S5); struct S6 { field: String, } impl PartialEq for S6 { fn eq(&self, other: &Self) -> bool { let mine = &self.field; let theirs = &other.field; mine == theirs // Should not warn! } } struct S7<'a> { field: &'a S7<'a>, } impl<'a> PartialEq for S7<'a> { fn eq(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing let mine = &self.field; let theirs = &other.field; mine == theirs } } struct S8 { num: i32, field: Option>, } impl PartialEq for S8 { fn eq(&self, other: &Self) -> bool { if self.num != other.num { return false; } let (this, other) = match (self.field.as_deref(), other.field.as_deref()) { (Some(x1), Some(x2)) => (x1, x2), (None, None) => return true, _ => return false, }; this == other } } struct S9; #[allow(clippy::to_string_trait_impl)] impl std::string::ToString for S9 { fn to_string(&self) -> String { //~^ ERROR: function cannot return without recursing self.to_string() } } struct S10; #[allow(clippy::to_string_trait_impl)] impl std::string::ToString for S10 { fn to_string(&self) -> String { //~^ ERROR: function cannot return without recursing let x = self; x.to_string() } } struct S11; #[allow(clippy::to_string_trait_impl)] impl std::string::ToString for S11 { fn to_string(&self) -> String { //~^ ERROR: function cannot return without recursing (self as &Self).to_string() } } struct S12; impl std::default::Default for S12 { fn default() -> Self { Self::new() } } impl S12 { fn new() -> Self { //~^ ERROR: function cannot return without recursing Self::default() } fn bar() -> Self { // Should not warn! Self::default() } } #[derive(Default)] struct S13 { f: u32, } impl S13 { fn new() -> Self { // Should not warn! Self::default() } } struct S14 { field: String, } impl PartialEq for S14 { fn eq(&self, other: &Self) -> bool { // Should not warn! self.field.eq(&other.field) } } struct S15<'a> { field: &'a S15<'a>, } impl PartialEq for S15<'_> { fn eq(&self, other: &Self) -> bool { //~^ ERROR: function cannot return without recursing let mine = &self.field; let theirs = &other.field; mine.eq(theirs) } } mod issue12154 { struct MyBox(T); impl std::ops::Deref for MyBox { type Target = T; fn deref(&self) -> &T { &self.0 } } impl PartialEq for MyBox { fn eq(&self, other: &Self) -> bool { (**self).eq(&**other) } } // Not necessarily related to the issue but another FP from the http crate that was fixed with it: // https://docs.rs/http/latest/src/http/header/name.rs.html#1424 // We used to simply peel refs from the LHS and RHS, so we couldn't differentiate // between `PartialEq for &T` and `PartialEq<&T> for T` impls. #[derive(PartialEq)] struct HeaderName; impl<'a> PartialEq<&'a HeaderName> for HeaderName { fn eq(&self, other: &&'a HeaderName) -> bool { *self == **other } } impl<'a> PartialEq for &'a HeaderName { fn eq(&self, other: &HeaderName) -> bool { *other == *self } } // Issue #12181 but also fixed by the same PR struct Foo; impl Foo { fn as_str(&self) -> &str { "Foo" } } impl PartialEq for Foo { fn eq(&self, other: &Self) -> bool { self.as_str().eq(other.as_str()) } } impl PartialEq for Foo where for<'a> &'a str: PartialEq, { fn eq(&self, other: &T) -> bool { (&self.as_str()).eq(other) } } } // From::from -> Into::into -> From::from struct BadFromTy1<'a>(&'a ()); struct BadIntoTy1<'b>(&'b ()); impl<'a> From> for BadIntoTy1<'static> { fn from(f: BadFromTy1<'a>) -> Self { f.into() } } // Using UFCS syntax struct BadFromTy2<'a>(&'a ()); struct BadIntoTy2<'b>(&'b ()); impl<'a> From> for BadIntoTy2<'static> { fn from(f: BadFromTy2<'a>) -> Self { Into::into(f) } } // Different Into impl (>), so no infinite recursion struct BadFromTy3; impl From for i32 { fn from(f: BadFromTy3) -> Self { Into::into(1i16) } } // A conditional return that ends the recursion struct BadFromTy4; impl From for i32 { fn from(f: BadFromTy4) -> Self { if true { return 42; } f.into() } } // Types differ in refs, don't lint impl From<&BadFromTy4> for i32 { fn from(f: &BadFromTy4) -> Self { BadFromTy4.into() } } fn main() {}