From 6f9eb6aa3ca0a173eadc74739ff5e135af18fd6c Mon Sep 17 00:00:00 2001 From: Seth Pink Date: Thu, 21 Feb 2013 14:57:27 +1000 Subject: [PATCH] Implement #[deriving_eq] on tuple like structs --- src/libsyntax/ext/deriving.rs | 103 +++++++++++++++--- .../deriving-via-extension-struct-empty.rs | 17 +++ .../deriving-via-extension-struct-tuple.rs | 26 +++++ 3 files changed, 132 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/deriving-via-extension-struct-empty.rs create mode 100644 src/test/run-pass/deriving-via-extension-struct-tuple.rs diff --git a/src/libsyntax/ext/deriving.rs b/src/libsyntax/ext/deriving.rs index 1aa1d8ca9a0..094eea81fd2 100644 --- a/src/libsyntax/ext/deriving.rs +++ b/src/libsyntax/ext/deriving.rs @@ -489,20 +489,36 @@ fn expand_deriving_eq_struct_def(cx: ext_ctxt, // Create the methods. let eq_ident = cx.ident_of(~"eq"); let ne_ident = cx.ident_of(~"ne"); - let eq_method = expand_deriving_eq_struct_method(cx, - span, - struct_def, - eq_ident, - type_ident, - ty_params, - Conjunction); - let ne_method = expand_deriving_eq_struct_method(cx, - span, - struct_def, - ne_ident, - type_ident, - ty_params, - Disjunction); + + let is_struct_tuple = + struct_def.fields.len() > 0 && struct_def.fields.all(|f| { + match f.node.kind { + named_field(*) => false, + unnamed_field => true + } + }); + + let derive_struct_fn = if is_struct_tuple { + expand_deriving_eq_struct_tuple_method + } else { + expand_deriving_eq_struct_method + }; + + + let eq_method = derive_struct_fn(cx, + span, + struct_def, + eq_ident, + type_ident, + ty_params, + Conjunction); + let ne_method = derive_struct_fn(cx, + span, + struct_def, + ne_ident, + type_ident, + ty_params, + Disjunction); // Create the implementation. return create_derived_eq_impl(cx, @@ -811,6 +827,65 @@ fn expand_deriving_eq_enum_method(cx: ext_ctxt, self_match_expr); } +fn expand_deriving_eq_struct_tuple_method(cx: ext_ctxt, + span: span, + struct_def: &struct_def, + method_ident: ident, + type_ident: ident, + ty_params: &[ty_param], + junction: Junction) + -> @method { + let self_str = ~"self"; + let other_str = ~"__other"; + let type_path = build::mk_raw_path(span, ~[type_ident]); + let fields = struct_def.fields; + + // Create comparison expression, comparing each of the fields + let mut match_body = None; + for fields.eachi |i, _| { + let other_field_ident = cx.ident_of(other_str + i.to_str()); + let other_field = build::mk_path(cx, span, ~[ other_field_ident ]); + + let self_field_ident = cx.ident_of(self_str + i.to_str()); + let self_field = build::mk_path(cx, span, ~[ self_field_ident ]); + + call_substructure_eq_method(cx, span, self_field, other_field, + method_ident, junction, &mut match_body); + } + let match_body = finish_eq_chain_expr(cx, span, match_body, junction); + + // Create arm for the '__other' match, containing the comparison expr + let other_subpats = create_subpatterns(cx, span, other_str, fields.len()); + let other_arm = ast::arm { + pats: ~[ build::mk_pat_enum(cx, span, type_path, other_subpats) ], + guard: None, + body: build::mk_simple_block(cx, span, match_body), + }; + + // Create the match on '__other' + let other_expr = build::mk_path(cx, span, ~[ cx.ident_of(other_str) ]); + let other_expr = build::mk_unary(cx, span, deref, other_expr); + let other_match_expr = expr_match(other_expr, ~[other_arm]); + let other_match_expr = build::mk_expr(cx, span, other_match_expr); + + // Create arm for the 'self' match, which contains the '__other' match + let self_subpats = create_subpatterns(cx, span, self_str, fields.len()); + let self_arm = ast::arm { + pats: ~[build::mk_pat_enum(cx, span, type_path, self_subpats)], + guard: None, + body: build::mk_simple_block(cx, span, other_match_expr), + }; + + // Create the match on 'self' + let self_expr = build::mk_path(cx, span, ~[ cx.ident_of(self_str) ]); + let self_expr = build::mk_unary(cx, span, deref, self_expr); + let self_match_expr = expr_match(self_expr, ~[self_arm]); + let self_match_expr = build::mk_expr(cx, span, self_match_expr); + + create_eq_method(cx, span, method_ident, + type_ident, ty_params, self_match_expr) +} + fn expand_deriving_iter_bytes_enum_method(cx: ext_ctxt, span: span, enum_definition: &enum_def) diff --git a/src/test/run-pass/deriving-via-extension-struct-empty.rs b/src/test/run-pass/deriving-via-extension-struct-empty.rs new file mode 100644 index 00000000000..70a13f972b8 --- /dev/null +++ b/src/test/run-pass/deriving-via-extension-struct-empty.rs @@ -0,0 +1,17 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving_eq] +struct Foo; + +pub fn main() { + assert Foo == Foo; + assert !(Foo != Foo); +} \ No newline at end of file diff --git a/src/test/run-pass/deriving-via-extension-struct-tuple.rs b/src/test/run-pass/deriving-via-extension-struct-tuple.rs new file mode 100644 index 00000000000..3a4f373fed2 --- /dev/null +++ b/src/test/run-pass/deriving-via-extension-struct-tuple.rs @@ -0,0 +1,26 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving_eq] +struct Foo(int, int, ~str); + +pub fn main() { + let a1 = Foo(5, 6, ~"abc"); + let a2 = Foo(5, 6, ~"abc"); + let b = Foo(5, 7, ~"def"); + + assert a1 == a1; + assert a1 == a2; + assert !(a1 == b); + + assert a1 != b; + assert !(a1 != a1); + assert !(a1 != a2); +}