diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 0c9535dfaa628..75a8cf32df8b2 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -42,6 +42,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use core::cmp::Ordering; use core::error::Error; use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] @@ -2530,12 +2531,51 @@ macro_rules! impl_eq { impl_eq! { String, str } impl_eq! { String, &'a str } +impl_eq! { String, &String } +impl_eq! { &String, str } #[cfg(not(no_global_oom_handling))] impl_eq! { Cow<'a, str>, str } #[cfg(not(no_global_oom_handling))] impl_eq! { Cow<'a, str>, &'b str } #[cfg(not(no_global_oom_handling))] impl_eq! { Cow<'a, str>, String } +#[cfg(not(no_global_oom_handling))] +impl_eq! { Cow<'a, str>, &String } + +macro_rules! impl_ord { + ($lhs:ty, $rhs: ty) => { + #[stable(feature = "string_partialord_impls", since = "CURRENT_RUSTC_VERSION")] + #[allow(unused_lifetimes)] + impl<'a, 'b> PartialOrd<$rhs> for $lhs { + #[inline] + fn partial_cmp(&self, other: &$rhs) -> Option { + PartialOrd::partial_cmp(&self[..], &other[..]) + } + } + + #[stable(feature = "string_partialord_impls", since = "CURRENT_RUSTC_VERSION")] + #[allow(unused_lifetimes)] + impl<'a, 'b> PartialOrd<$lhs> for $rhs { + #[inline] + fn partial_cmp(&self, other: &$lhs) -> Option { + PartialOrd::partial_cmp(&self[..], &other[..]) + } + } + }; +} + +impl_ord! { String, str } +impl_ord! { String, &'a str } +impl_ord! { &String, str } +impl_ord! { String, &String } +#[cfg(not(no_global_oom_handling))] +impl_ord! { Cow<'a, str>, str } +#[cfg(not(no_global_oom_handling))] +impl_ord! { Cow<'a, str>, &'b str } +#[cfg(not(no_global_oom_handling))] +impl_ord! { Cow<'a, str>, String } +#[cfg(not(no_global_oom_handling))] +impl_ord! { Cow<'a, str>, &String } #[stable(feature = "rust1", since = "1.0.0")] impl Default for String { diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 77c70b978fd15..47b63e526050a 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -30,6 +30,22 @@ impl PartialEq for str { } } +#[stable(feature = "more_str_partialeq_impls", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<&str> for str { + #[inline] + fn eq(&self, other: &&str) -> bool { + self.as_bytes() == other.as_bytes() + } +} + +#[stable(feature = "more_str_partialeq_impls", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq for &str { + #[inline] + fn eq(&self, other: &str) -> bool { + self.as_bytes() == other.as_bytes() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Eq for str {} @@ -48,6 +64,22 @@ impl PartialOrd for str { } } +#[stable(feature = "more_str_partialord_impls", since = "CURRENT_RUSTC_VERSION")] +impl PartialOrd<&str> for str { + #[inline] + fn partial_cmp(&self, other: &&str) -> Option { + Some(self.cmp(*other)) + } +} + +#[stable(feature = "more_str_partialord_impls", since = "CURRENT_RUSTC_VERSION")] +impl PartialOrd for &str { + #[inline] + fn partial_cmp(&self, other: &str) -> Option { + Some(self.cmp(&other)) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index for str where diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index fe8c89f7a5394..8252df8001858 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -77,7 +77,8 @@ pub fn get_clippy_rules_in_order(all_args: &[String], config: &LintConfig) -> Ve let rule = format!("{prefix}{v}"); // Arguments added by bootstrap in LintConfig won't show up in the all_args list, so // put them at the end of the command line. - let position = all_args.iter().position(|t| t == &rule || t == v).unwrap_or(usize::MAX); + let position = + all_args.iter().position(|t| t == rule.as_str() || t == v).unwrap_or(usize::MAX); result.push((position, rule)); }); } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index cf6b8992973a7..4ebed850e738d 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -98,12 +98,12 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) let arg_snip = snippet(cx, arg_span, ".."); let expr_snip; let eq_impl; - if with_deref.is_implemented() { - expr_snip = format!("*{arg_snip}"); - eq_impl = with_deref; - } else { + if without_deref.is_implemented() { expr_snip = arg_snip.to_string(); eq_impl = without_deref; + } else { + expr_snip = format!("*{arg_snip}"); + eq_impl = with_deref; } let span; diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed index d7d3d299349ee..4c5bb6c9ee24d 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed @@ -13,13 +13,13 @@ fn main() { let _: Option = vec.iter().chain(vec.iter()).next().cloned(); - let _: usize = vec.iter().filter(|x| x == &"2").count(); + let _: usize = vec.iter().filter(|x| x == "2").count(); let _: Vec<_> = vec.iter().take(2).cloned().collect(); let _: Vec<_> = vec.iter().skip(2).cloned().collect(); - let _ = vec.iter().filter(|x| x == &"2").nth(2).cloned(); + let _ = vec.iter().filter(|x| x == "2").nth(2).cloned(); let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] .iter() @@ -46,7 +46,7 @@ fn main() { iter: impl Iterator + 'a, target: String, ) -> impl Iterator + 'a { - iter.filter(move |&(&a, b)| a == 1 && b == &target).cloned() + iter.filter(move |&(&a, b)| a == 1 && b == target).cloned() } { @@ -57,7 +57,7 @@ fn main() { } fn bar<'a>(iter: impl Iterator> + 'a, target: String) -> impl Iterator> + 'a { - iter.filter(move |&S { a, b }| **a == 1 && b == &target).cloned() + iter.filter(move |&S { a, b }| **a == 1 && b == target).cloned() } } diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs index 45e1349febd06..3a4e449e1da20 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs @@ -47,7 +47,7 @@ fn main() { iter: impl Iterator + 'a, target: String, ) -> impl Iterator + 'a { - iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) + iter.cloned().filter(move |(&a, b)| a == 1 && b == target) } { @@ -58,7 +58,7 @@ fn main() { } fn bar<'a>(iter: impl Iterator> + 'a, target: String) -> impl Iterator> + 'a { - iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target) + iter.cloned().filter(move |S { a, b }| **a == 1 && b == target) } } diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr index e6680266f1076..12d316171031b 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr @@ -28,6 +28,17 @@ LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); = note: `-D clippy::redundant-clone` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` +error: taken reference of right operand + --> tests/ui/iter_overeager_cloned.rs:16:42 + | +LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); + | ^^^^^---- + | | + | help: use the right value directly: `"2"` + | + = note: `-D clippy::op-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::op_ref)]` + error: unnecessarily eager cloning of iterator items --> tests/ui/iter_overeager_cloned.rs:18:21 | @@ -52,6 +63,14 @@ LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); | | | help: try: `.nth(2).cloned()` +error: taken reference of right operand + --> tests/ui/iter_overeager_cloned.rs:22:35 + | +LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); + | ^^^^^---- + | | + | help: use the right value directly: `"2"` + error: unnecessarily eager cloning of iterator items --> tests/ui/iter_overeager_cloned.rs:24:13 | @@ -119,18 +138,18 @@ LL | let _ = vec.iter().cloned().find(f); error: unnecessarily eager cloning of iterator items --> tests/ui/iter_overeager_cloned.rs:50:9 | -LL | iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) - | ^^^^------------------------------------------------------- +LL | iter.cloned().filter(move |(&a, b)| a == 1 && b == target) + | ^^^^------------------------------------------------------ | | - | help: try: `.filter(move |&(&a, b)| a == 1 && b == &target).cloned()` + | help: try: `.filter(move |&(&a, b)| a == 1 && b == target).cloned()` error: unnecessarily eager cloning of iterator items --> tests/ui/iter_overeager_cloned.rs:61:13 | -LL | iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target) - | ^^^^------------------------------------------------------------ +LL | iter.cloned().filter(move |S { a, b }| **a == 1 && b == target) + | ^^^^----------------------------------------------------------- | | - | help: try: `.filter(move |&S { a, b }| **a == 1 && b == &target).cloned()` + | help: try: `.filter(move |&S { a, b }| **a == 1 && b == target).cloned()` error: unneeded cloning of iterator items --> tests/ui/iter_overeager_cloned.rs:65:13 @@ -164,5 +183,5 @@ LL | let _ = vec.iter().cloned().any(|x| x.len() == 1); | | | help: try: `.any(|x| x.len() == 1)` -error: aborting due to 19 previous errors +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/op_ref.fixed b/src/tools/clippy/tests/ui/op_ref.fixed index 183dcf4f08635..0079515538d74 100644 --- a/src/tools/clippy/tests/ui/op_ref.fixed +++ b/src/tools/clippy/tests/ui/op_ref.fixed @@ -18,7 +18,7 @@ fn main() { let a = "a".to_string(); let b = "a"; - if b < &a { + if b < a { println!("OK"); } diff --git a/src/tools/clippy/tests/ui/op_ref.stderr b/src/tools/clippy/tests/ui/op_ref.stderr index c5b68730a8f26..ae2f1eaf352dc 100644 --- a/src/tools/clippy/tests/ui/op_ref.stderr +++ b/src/tools/clippy/tests/ui/op_ref.stderr @@ -11,6 +11,14 @@ help: use the values directly LL | let foo = 5 - 6; | ~ ~ +error: taken reference of right operand + --> tests/ui/op_ref.rs:21:8 + | +LL | if b < &a { + | ^^^^-- + | | + | help: use the right value directly: `a` + error: taken reference of right operand --> tests/ui/op_ref.rs:58:13 | @@ -35,5 +43,5 @@ LL | let _ = two + &three; | | | help: use the right value directly: `three` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/binop/binary-op-suggest-deref.rs b/tests/ui/binop/binary-op-suggest-deref.rs index ae442a0d0b481..3cf2d3326732b 100644 --- a/tests/ui/binop/binary-op-suggest-deref.rs +++ b/tests/ui/binop/binary-op-suggest-deref.rs @@ -67,9 +67,7 @@ fn baz() { let string_ref = &owned; let partial = "foobar"; _ = string_ref == partial[..3]; - //~^ERROR can't compare `&String` with `str` [E0277] _ = partial[..3] == string_ref; - //~^ERROR can't compare `str` with `&String` [E0277] } fn qux() { diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index 440625d8ccbac..a39f669c97e5f 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -271,32 +271,8 @@ note: an implementation of `PartialEq<&&{integer}>` might be missing for `Foo` LL | struct Foo; | ^^^^^^^^^^ must implement `PartialEq<&&{integer}>` -error[E0277]: can't compare `&String` with `str` - --> $DIR/binary-op-suggest-deref.rs:69:20 - | -LL | _ = string_ref == partial[..3]; - | ^^ no implementation for `&String == str` - | - = help: the trait `PartialEq` is not implemented for `&String` -help: consider dereferencing here - | -LL | _ = *string_ref == partial[..3]; - | + - -error[E0277]: can't compare `str` with `&String` - --> $DIR/binary-op-suggest-deref.rs:71:22 - | -LL | _ = partial[..3] == string_ref; - | ^^ no implementation for `str == &String` - | - = help: the trait `PartialEq<&String>` is not implemented for `str` -help: consider dereferencing here - | -LL | _ = partial[..3] == *string_ref; - | + - error[E0277]: no implementation for `i32 & str` - --> $DIR/binary-op-suggest-deref.rs:78:17 + --> $DIR/binary-op-suggest-deref.rs:76:17 | LL | let _ = FOO & (*"Sized".to_string().into_boxed_str()); | ^ no implementation for `i32 & str` @@ -309,14 +285,14 @@ LL | let _ = FOO & (*"Sized".to_string().into_boxed_str()); `i32` implements `BitAnd` error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/binary-op-suggest-deref.rs:78:17 + --> $DIR/binary-op-suggest-deref.rs:76:17 | LL | let _ = FOO & (*"Sized".to_string().into_boxed_str()); | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` -error: aborting due to 24 previous errors +error: aborting due to 22 previous errors Some errors have detailed explanations: E0277, E0308, E0369. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/inference/issue-72616.stderr b/tests/ui/inference/issue-72616.stderr index a26f9a1ff5618..1470d0e2ab48a 100644 --- a/tests/ui/inference/issue-72616.stderr +++ b/tests/ui/inference/issue-72616.stderr @@ -8,12 +8,15 @@ LL | if String::from("a") == "a".try_into().unwrap() {} | = note: cannot satisfy `String: PartialEq<_>` = help: the following types implement trait `PartialEq`: + `&String` implements `PartialEq>` + `&String` implements `PartialEq` + `&String` implements `PartialEq` + `String` implements `PartialEq<&String>` `String` implements `PartialEq<&str>` `String` implements `PartialEq` `String` implements `PartialEq` `String` implements `PartialEq>` - `String` implements `PartialEq` - `String` implements `PartialEq` + and 2 others help: try using a fully qualified path to specify the expected types | LL | if String::from("a") == <&str as TryInto>::try_into("a").unwrap() {}