rust-clippy/tests/ui/unconditional_recursion.rs
2024-04-10 08:37:02 -04:00

401 lines
8 KiB
Rust

//@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: PartialEq>(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<Box<S8>>,
}
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>(T);
impl<T> std::ops::Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: PartialEq> PartialEq for MyBox<T> {
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<T> 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<HeaderName> 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<T> PartialEq<T> for Foo
where
for<'a> &'a str: PartialEq<T>,
{
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<BadFromTy1<'a>> 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<BadFromTy2<'a>> for BadIntoTy2<'static> {
fn from(f: BadFromTy2<'a>) -> Self {
Into::into(f)
}
}
// Different Into impl (<i16 as Into<i32>>), so no infinite recursion
struct BadFromTy3;
impl From<BadFromTy3> for i32 {
fn from(f: BadFromTy3) -> Self {
Into::into(1i16)
}
}
// A conditional return that ends the recursion
struct BadFromTy4;
impl From<BadFromTy4> 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() {}