Skip to content

Commit e0767bf

Browse files
committed
auto merge of #5068 : sethpink/rust/derive-eq-tuple-struct, r=catamorphism
Previously an unimplemented error was thrown when using #[deriving_eq] on tuple-like struct definitions.
2 parents 4a5e8c5 + 6f9eb6a commit e0767bf

File tree

3 files changed

+132
-14
lines changed

3 files changed

+132
-14
lines changed

src/libsyntax/ext/deriving.rs

+89-14
Original file line numberDiff line numberDiff line change
@@ -489,20 +489,36 @@ fn expand_deriving_eq_struct_def(cx: ext_ctxt,
489489
// Create the methods.
490490
let eq_ident = cx.ident_of(~"eq");
491491
let ne_ident = cx.ident_of(~"ne");
492-
let eq_method = expand_deriving_eq_struct_method(cx,
493-
span,
494-
struct_def,
495-
eq_ident,
496-
type_ident,
497-
ty_params,
498-
Conjunction);
499-
let ne_method = expand_deriving_eq_struct_method(cx,
500-
span,
501-
struct_def,
502-
ne_ident,
503-
type_ident,
504-
ty_params,
505-
Disjunction);
492+
493+
let is_struct_tuple =
494+
struct_def.fields.len() > 0 && struct_def.fields.all(|f| {
495+
match f.node.kind {
496+
named_field(*) => false,
497+
unnamed_field => true
498+
}
499+
});
500+
501+
let derive_struct_fn = if is_struct_tuple {
502+
expand_deriving_eq_struct_tuple_method
503+
} else {
504+
expand_deriving_eq_struct_method
505+
};
506+
507+
508+
let eq_method = derive_struct_fn(cx,
509+
span,
510+
struct_def,
511+
eq_ident,
512+
type_ident,
513+
ty_params,
514+
Conjunction);
515+
let ne_method = derive_struct_fn(cx,
516+
span,
517+
struct_def,
518+
ne_ident,
519+
type_ident,
520+
ty_params,
521+
Disjunction);
506522

507523
// Create the implementation.
508524
return create_derived_eq_impl(cx,
@@ -811,6 +827,65 @@ fn expand_deriving_eq_enum_method(cx: ext_ctxt,
811827
self_match_expr);
812828
}
813829

830+
fn expand_deriving_eq_struct_tuple_method(cx: ext_ctxt,
831+
span: span,
832+
struct_def: &struct_def,
833+
method_ident: ident,
834+
type_ident: ident,
835+
ty_params: &[ty_param],
836+
junction: Junction)
837+
-> @method {
838+
let self_str = ~"self";
839+
let other_str = ~"__other";
840+
let type_path = build::mk_raw_path(span, ~[type_ident]);
841+
let fields = struct_def.fields;
842+
843+
// Create comparison expression, comparing each of the fields
844+
let mut match_body = None;
845+
for fields.eachi |i, _| {
846+
let other_field_ident = cx.ident_of(other_str + i.to_str());
847+
let other_field = build::mk_path(cx, span, ~[ other_field_ident ]);
848+
849+
let self_field_ident = cx.ident_of(self_str + i.to_str());
850+
let self_field = build::mk_path(cx, span, ~[ self_field_ident ]);
851+
852+
call_substructure_eq_method(cx, span, self_field, other_field,
853+
method_ident, junction, &mut match_body);
854+
}
855+
let match_body = finish_eq_chain_expr(cx, span, match_body, junction);
856+
857+
// Create arm for the '__other' match, containing the comparison expr
858+
let other_subpats = create_subpatterns(cx, span, other_str, fields.len());
859+
let other_arm = ast::arm {
860+
pats: ~[ build::mk_pat_enum(cx, span, type_path, other_subpats) ],
861+
guard: None,
862+
body: build::mk_simple_block(cx, span, match_body),
863+
};
864+
865+
// Create the match on '__other'
866+
let other_expr = build::mk_path(cx, span, ~[ cx.ident_of(other_str) ]);
867+
let other_expr = build::mk_unary(cx, span, deref, other_expr);
868+
let other_match_expr = expr_match(other_expr, ~[other_arm]);
869+
let other_match_expr = build::mk_expr(cx, span, other_match_expr);
870+
871+
// Create arm for the 'self' match, which contains the '__other' match
872+
let self_subpats = create_subpatterns(cx, span, self_str, fields.len());
873+
let self_arm = ast::arm {
874+
pats: ~[build::mk_pat_enum(cx, span, type_path, self_subpats)],
875+
guard: None,
876+
body: build::mk_simple_block(cx, span, other_match_expr),
877+
};
878+
879+
// Create the match on 'self'
880+
let self_expr = build::mk_path(cx, span, ~[ cx.ident_of(self_str) ]);
881+
let self_expr = build::mk_unary(cx, span, deref, self_expr);
882+
let self_match_expr = expr_match(self_expr, ~[self_arm]);
883+
let self_match_expr = build::mk_expr(cx, span, self_match_expr);
884+
885+
create_eq_method(cx, span, method_ident,
886+
type_ident, ty_params, self_match_expr)
887+
}
888+
814889
fn expand_deriving_iter_bytes_enum_method(cx: ext_ctxt,
815890
span: span,
816891
enum_definition: &enum_def)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2013 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+
#[deriving_eq]
12+
struct Foo;
13+
14+
pub fn main() {
15+
assert Foo == Foo;
16+
assert !(Foo != Foo);
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2013 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+
#[deriving_eq]
12+
struct Foo(int, int, ~str);
13+
14+
pub fn main() {
15+
let a1 = Foo(5, 6, ~"abc");
16+
let a2 = Foo(5, 6, ~"abc");
17+
let b = Foo(5, 7, ~"def");
18+
19+
assert a1 == a1;
20+
assert a1 == a2;
21+
assert !(a1 == b);
22+
23+
assert a1 != b;
24+
assert !(a1 != a1);
25+
assert !(a1 != a2);
26+
}

0 commit comments

Comments
 (0)