Skip to content

Commit e5288c9

Browse files
Rollup merge of rust-lang#43011 - qnighy:unsized-tuple-impls, r=aturon
Implement Eq/Hash/Debug etc. for unsized tuples. As I mentioned in [the comment in rust-lang#18469](rust-lang#18469 (comment)), the implementations of `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Debug`, `Hash` can be generalized to unsized tuples. This is consistent with the `derive` behavior for unsized structs. ```rust #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] struct MyTuple<X, Y, Z: ?Sized>(X, Y, Z); fn f(x: &MyTuple<i32, i32, [i32]>) { x == x; x < x; println!("{:?}", x); } ``` Questions: - Need an RFC? - Need a feature gate? I don't think it does because the unsized tuple coercion rust-lang#42527 is feature-gated. - I changed `builder.field($name);` into `builder.field(&$name);` in the `Debug` implementation to pass compilation. This won't affect the behavior because `Debug for &'a T` is a mere redirection to `Debug for T`. However, I don't know if it affects code size / performance.
2 parents 1a7dc0a + 728d26c commit e5288c9

File tree

4 files changed

+52
-7
lines changed

4 files changed

+52
-7
lines changed

src/libcore/fmt/mod.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1627,13 +1627,13 @@ macro_rules! tuple {
16271627
() => ();
16281628
( $($name:ident,)+ ) => (
16291629
#[stable(feature = "rust1", since = "1.0.0")]
1630-
impl<$($name:Debug),*> Debug for ($($name,)*) {
1630+
impl<$($name:Debug),*> Debug for ($($name,)*) where last_type!($($name,)+): ?Sized {
16311631
#[allow(non_snake_case, unused_assignments, deprecated)]
16321632
fn fmt(&self, f: &mut Formatter) -> Result {
16331633
let mut builder = f.debug_tuple("");
16341634
let ($(ref $name,)*) = *self;
16351635
$(
1636-
builder.field($name);
1636+
builder.field(&$name);
16371637
)*
16381638

16391639
builder.finish()
@@ -1643,6 +1643,11 @@ macro_rules! tuple {
16431643
)
16441644
}
16451645

1646+
macro_rules! last_type {
1647+
($a:ident,) => { $a };
1648+
($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
1649+
}
1650+
16461651
tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
16471652

16481653
#[stable(feature = "rust1", since = "1.0.0")]

src/libcore/hash/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ mod impls {
559559

560560
( $($name:ident)+) => (
561561
#[stable(feature = "rust1", since = "1.0.0")]
562-
impl<$($name: Hash),*> Hash for ($($name,)*) {
562+
impl<$($name: Hash),*> Hash for ($($name,)*) where last_type!($($name,)+): ?Sized {
563563
#[allow(non_snake_case)]
564564
fn hash<S: Hasher>(&self, state: &mut S) {
565565
let ($(ref $name,)*) = *self;
@@ -569,6 +569,11 @@ mod impls {
569569
);
570570
}
571571

572+
macro_rules! last_type {
573+
($a:ident,) => { $a };
574+
($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
575+
}
576+
572577
impl_hash_tuple! {}
573578
impl_hash_tuple! { A }
574579
impl_hash_tuple! { A B }

src/libcore/tuple.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ macro_rules! tuple_impls {
2929
}
3030

3131
#[stable(feature = "rust1", since = "1.0.0")]
32-
impl<$($T:PartialEq),+> PartialEq for ($($T,)+) {
32+
impl<$($T:PartialEq),+> PartialEq for ($($T,)+) where last_type!($($T,)+): ?Sized {
3333
#[inline]
3434
fn eq(&self, other: &($($T,)+)) -> bool {
3535
$(self.$idx == other.$idx)&&+
@@ -41,10 +41,11 @@ macro_rules! tuple_impls {
4141
}
4242

4343
#[stable(feature = "rust1", since = "1.0.0")]
44-
impl<$($T:Eq),+> Eq for ($($T,)+) {}
44+
impl<$($T:Eq),+> Eq for ($($T,)+) where last_type!($($T,)+): ?Sized {}
4545

4646
#[stable(feature = "rust1", since = "1.0.0")]
47-
impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+) {
47+
impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+)
48+
where last_type!($($T,)+): ?Sized {
4849
#[inline]
4950
fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
5051
lexical_partial_cmp!($(self.$idx, other.$idx),+)
@@ -68,7 +69,7 @@ macro_rules! tuple_impls {
6869
}
6970

7071
#[stable(feature = "rust1", since = "1.0.0")]
71-
impl<$($T:Ord),+> Ord for ($($T,)+) {
72+
impl<$($T:Ord),+> Ord for ($($T,)+) where last_type!($($T,)+): ?Sized {
7273
#[inline]
7374
fn cmp(&self, other: &($($T,)+)) -> Ordering {
7475
lexical_cmp!($(self.$idx, other.$idx),+)
@@ -118,6 +119,11 @@ macro_rules! lexical_cmp {
118119
($a:expr, $b:expr) => { ($a).cmp(&$b) };
119120
}
120121

122+
macro_rules! last_type {
123+
($a:ident,) => { $a };
124+
($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
125+
}
126+
121127
tuple_impls! {
122128
Tuple1 {
123129
(0) -> A
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(unsized_tuple_coercion)]
12+
13+
use std::collections::HashSet;
14+
15+
fn main() {
16+
let x : &(i32, i32, [i32]) = &(0, 1, [2, 3]);
17+
let y : &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]);
18+
let mut a = [y, x];
19+
a.sort();
20+
assert_eq!(a, [x, y]);
21+
22+
assert_eq!(&format!("{:?}", a), "[(0, 1, [2, 3]), (0, 1, [2, 3, 4])]");
23+
24+
let mut h = HashSet::new();
25+
h.insert(x);
26+
h.insert(y);
27+
assert!(h.contains(x));
28+
assert!(h.contains(y));
29+
}

0 commit comments

Comments
 (0)