Skip to content

Commit 7abdc84

Browse files
committed
Auto merge of #135536 - joshtriplett:str-impls, r=<try>
Add more impls of PartialEq and PartialOrd for strings Currently, some combinations of `&String` and `&str` don't support comparison operators. For instance, this: ```rust fn main() { let s1 = String::from("hello"); let s2 = "world"; _ = s1 < s2; } ``` will fail with: ``` error[E0308]: mismatched types --> src/main.rs:4:14 | 4 | _ = s1 < s2; | -- ^^- help: try using a conversion method: `.to_string()` | | | | | expected `String`, found `&str` | expected because this is `String` ``` Other combinations only work because the compiler implicitly relies on impls on different reference types, and that makes such combinations fragile, breaking if any other impls of `PartialOrd` show up. Add some additional impls to make such cases work, and to improve robustness when adding other impls in the future. In particular, I'm hoping that adding these makes it possible to add comparisons with other stringy types without creating as many inference issues.
2 parents 2776bdf + 8b933dd commit 7abdc84

File tree

4 files changed

+73
-29
lines changed

4 files changed

+73
-29
lines changed

library/alloc/src/string.rs

+38
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
4343
#![stable(feature = "rust1", since = "1.0.0")]
4444

45+
use core::cmp::Ordering;
4546
use core::error::Error;
4647
use core::iter::FusedIterator;
4748
#[cfg(not(no_global_oom_handling))]
@@ -2530,12 +2531,49 @@ macro_rules! impl_eq {
25302531

25312532
impl_eq! { String, str }
25322533
impl_eq! { String, &'a str }
2534+
impl_eq! { &String, str }
25332535
#[cfg(not(no_global_oom_handling))]
25342536
impl_eq! { Cow<'a, str>, str }
25352537
#[cfg(not(no_global_oom_handling))]
25362538
impl_eq! { Cow<'a, str>, &'b str }
25372539
#[cfg(not(no_global_oom_handling))]
25382540
impl_eq! { Cow<'a, str>, String }
2541+
#[cfg(not(no_global_oom_handling))]
2542+
impl_eq! { Cow<'a, str>, &String }
2543+
2544+
macro_rules! impl_ord {
2545+
($lhs:ty, $rhs: ty) => {
2546+
#[stable(feature = "rust1", since = "1.0.0")]
2547+
#[allow(unused_lifetimes)]
2548+
impl<'a, 'b> PartialOrd<$rhs> for $lhs {
2549+
#[inline]
2550+
fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
2551+
PartialOrd::partial_cmp(&self[..], &other[..])
2552+
}
2553+
}
2554+
2555+
#[stable(feature = "rust1", since = "1.0.0")]
2556+
#[allow(unused_lifetimes)]
2557+
impl<'a, 'b> PartialOrd<$lhs> for $rhs {
2558+
#[inline]
2559+
fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
2560+
PartialOrd::partial_cmp(&self[..], &other[..])
2561+
}
2562+
}
2563+
};
2564+
}
2565+
2566+
impl_ord! { String, str }
2567+
impl_ord! { String, &'a str }
2568+
impl_ord! { &String, str }
2569+
#[cfg(not(no_global_oom_handling))]
2570+
impl_ord! { Cow<'a, str>, str }
2571+
#[cfg(not(no_global_oom_handling))]
2572+
impl_ord! { Cow<'a, str>, &'b str }
2573+
#[cfg(not(no_global_oom_handling))]
2574+
impl_ord! { Cow<'a, str>, String }
2575+
#[cfg(not(no_global_oom_handling))]
2576+
impl_ord! { Cow<'a, str>, &String }
25392577

25402578
#[stable(feature = "rust1", since = "1.0.0")]
25412579
impl Default for String {

library/core/src/str/traits.rs

+32
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ impl PartialEq for str {
3030
}
3131
}
3232

33+
#[stable(feature = "rust1", since = "1.0.0")]
34+
impl PartialEq<&str> for str {
35+
#[inline]
36+
fn eq(&self, other: &&str) -> bool {
37+
self.as_bytes() == other.as_bytes()
38+
}
39+
}
40+
41+
#[stable(feature = "rust1", since = "1.0.0")]
42+
impl PartialEq<str> for &str {
43+
#[inline]
44+
fn eq(&self, other: &str) -> bool {
45+
self.as_bytes() == other.as_bytes()
46+
}
47+
}
48+
3349
#[stable(feature = "rust1", since = "1.0.0")]
3450
impl Eq for str {}
3551

@@ -48,6 +64,22 @@ impl PartialOrd for str {
4864
}
4965
}
5066

67+
#[stable(feature = "rust1", since = "1.0.0")]
68+
impl PartialOrd<&str> for str {
69+
#[inline]
70+
fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
71+
Some(self.cmp(*other))
72+
}
73+
}
74+
75+
#[stable(feature = "rust1", since = "1.0.0")]
76+
impl PartialOrd<str> for &str {
77+
#[inline]
78+
fn partial_cmp(&self, other: &str) -> Option<Ordering> {
79+
Some(self.cmp(&other))
80+
}
81+
}
82+
5183
#[stable(feature = "rust1", since = "1.0.0")]
5284
impl<I> ops::Index<I> for str
5385
where

tests/ui/binop/binary-op-suggest-deref.rs

-2
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,7 @@ fn baz() {
6767
let string_ref = &owned;
6868
let partial = "foobar";
6969
_ = string_ref == partial[..3];
70-
//~^ERROR can't compare `&String` with `str` [E0277]
7170
_ = partial[..3] == string_ref;
72-
//~^ERROR can't compare `str` with `&String` [E0277]
7371
}
7472

7573
fn qux() {

tests/ui/binop/binary-op-suggest-deref.stderr

+3-27
Original file line numberDiff line numberDiff line change
@@ -271,32 +271,8 @@ note: an implementation of `PartialEq<&&{integer}>` might be missing for `Foo`
271271
LL | struct Foo;
272272
| ^^^^^^^^^^ must implement `PartialEq<&&{integer}>`
273273

274-
error[E0277]: can't compare `&String` with `str`
275-
--> $DIR/binary-op-suggest-deref.rs:69:20
276-
|
277-
LL | _ = string_ref == partial[..3];
278-
| ^^ no implementation for `&String == str`
279-
|
280-
= help: the trait `PartialEq<str>` is not implemented for `&String`
281-
help: consider dereferencing here
282-
|
283-
LL | _ = *string_ref == partial[..3];
284-
| +
285-
286-
error[E0277]: can't compare `str` with `&String`
287-
--> $DIR/binary-op-suggest-deref.rs:71:22
288-
|
289-
LL | _ = partial[..3] == string_ref;
290-
| ^^ no implementation for `str == &String`
291-
|
292-
= help: the trait `PartialEq<&String>` is not implemented for `str`
293-
help: consider dereferencing here
294-
|
295-
LL | _ = partial[..3] == *string_ref;
296-
| +
297-
298274
error[E0277]: no implementation for `i32 & str`
299-
--> $DIR/binary-op-suggest-deref.rs:78:17
275+
--> $DIR/binary-op-suggest-deref.rs:76:17
300276
|
301277
LL | let _ = FOO & (*"Sized".to_string().into_boxed_str());
302278
| ^ no implementation for `i32 & str`
@@ -309,14 +285,14 @@ LL | let _ = FOO & (*"Sized".to_string().into_boxed_str());
309285
`i32` implements `BitAnd`
310286

311287
error[E0277]: the size for values of type `str` cannot be known at compilation time
312-
--> $DIR/binary-op-suggest-deref.rs:78:17
288+
--> $DIR/binary-op-suggest-deref.rs:76:17
313289
|
314290
LL | let _ = FOO & (*"Sized".to_string().into_boxed_str());
315291
| ^ doesn't have a size known at compile-time
316292
|
317293
= help: the trait `Sized` is not implemented for `str`
318294

319-
error: aborting due to 24 previous errors
295+
error: aborting due to 22 previous errors
320296

321297
Some errors have detailed explanations: E0277, E0308, E0369.
322298
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)