From 77b21fa4982c5e2dc917ac15f6f32191d6b5af92 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Thu, 2 Apr 2015 09:14:53 -0700 Subject: [PATCH 1/9] syntax: Rename deriving/cmp/* to match their current names --- src/libsyntax/ext/deriving/cmp/eq.rs | 86 +++---- src/libsyntax/ext/deriving/cmp/ord.rs | 184 ++++---------- src/libsyntax/ext/deriving/cmp/partial_eq.rs | 95 +++++++ src/libsyntax/ext/deriving/cmp/partial_ord.rs | 238 ++++++++++++++++++ src/libsyntax/ext/deriving/cmp/totaleq.rs | 69 ----- src/libsyntax/ext/deriving/cmp/totalord.rs | 142 ----------- src/libsyntax/ext/deriving/mod.rs | 16 +- 7 files changed, 415 insertions(+), 415 deletions(-) create mode 100644 src/libsyntax/ext/deriving/cmp/partial_eq.rs create mode 100644 src/libsyntax/ext/deriving/cmp/partial_ord.rs delete mode 100644 src/libsyntax/ext/deriving/cmp/totaleq.rs delete mode 100644 src/libsyntax/ext/deriving/cmp/totalord.rs diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index c02af437b1c7b..6418450685e39 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{MetaItem, Item, Expr, self}; +use ast::{MetaItem, Item, Expr}; use codemap::Span; use ext::base::ExtCtxt; use ext::build::AstBuilder; @@ -24,70 +24,44 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, push: F) where F: FnOnce(P), { - // structures are equal if all fields are equal, and non equal, if - // any fields are not equal or if the enum variants are different - fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match other_fs { - [ref o_f] => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - }; - - let eq = cx.expr_binary(span, ast::BiEq, self_f, other_f.clone()); - - cx.expr_binary(span, ast::BiAnd, subexpr, eq) - }, - cx.expr_bool(span, true), - Box::new(|cx, span, _, _| cx.expr_bool(span, false)), - cx, span, substr) - } - fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match other_fs { - [ref o_f] => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - }; - - let eq = cx.expr_binary(span, ast::BiNe, self_f, other_f.clone()); - - cx.expr_binary(span, ast::BiOr, subexpr, eq) - }, - cx.expr_bool(span, false), - Box::new(|cx, span, _, _| cx.expr_bool(span, true)), - cx, span, substr) + fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { + cs_same_method(|cx, span, exprs| { + // create `a.(); b.(); c.(); ...` + // (where method is `assert_receiver_is_total_eq`) + let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); + let block = cx.block(span, stmts, None); + cx.expr_block(block) + }, + Box::new(|cx, sp, _, _| { + cx.span_bug(sp, "non matching enums in derive(Eq)?") }), + cx, + span, + substr) } - macro_rules! md { - ($name:expr, $f:ident) => { { - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let inline = cx.meta_word(span, InternedString::new("inline")); + let hidden = cx.meta_word(span, InternedString::new("hidden")); + let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden)); + let attrs = vec!(cx.attribute(span, inline), + cx.attribute(span, doc)); + let trait_def = TraitDef { + span: span, + attributes: Vec::new(), + path: path_std!(cx, core::cmp::Eq), + additional_bounds: Vec::new(), + generics: LifetimeBounds::empty(), + methods: vec!( MethodDef { - name: $name, + name: "assert_receiver_is_total_eq", generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), - ret_ty: Literal(path_local!(bool)), + args: vec!(), + ret_ty: nil_ty(), attributes: attrs, combine_substructure: combine_substructure(Box::new(|a, b, c| { - $f(a, b, c) + cs_total_eq_assert(a, b, c) })) } - } } - } - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::cmp::PartialEq), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - methods: vec!( - md!("eq", cs_eq), - md!("ne", cs_ne) ), associated_types: Vec::new(), }; diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index 8ecd172b2f0d8..1de955856e712 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::OrderingOp::*; - use ast; use ast::{MetaItem, Item, Expr}; use codemap::Span; @@ -20,114 +18,72 @@ use ext::deriving::generic::ty::*; use parse::token::InternedString; use ptr::P; -pub fn expand_deriving_ord(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where +pub fn expand_deriving_totalord(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: F) where F: FnOnce(P), { - macro_rules! md { - ($name:expr, $op:expr, $equal:expr) => { { - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let inline = cx.meta_word(span, InternedString::new("inline")); + let attrs = vec!(cx.attribute(span, inline)); + let trait_def = TraitDef { + span: span, + attributes: Vec::new(), + path: path_std!(cx, core::cmp::Ord), + additional_bounds: Vec::new(), + generics: LifetimeBounds::empty(), + methods: vec!( MethodDef { - name: $name, + name: "cmp", generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec!(borrowed_self()), - ret_ty: Literal(path_local!(bool)), + ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), attributes: attrs, - combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_op($op, $equal, cx, span, substr) - })) + combine_substructure: combine_substructure(Box::new(|a, b, c| { + cs_cmp(a, b, c) + })), } - } } - } - - let ordering_ty = Literal(path_std!(cx, core::cmp::Ordering)); - let ret_ty = Literal(Path::new_(pathvec_std!(cx, core::option::Option), - None, - vec![box ordering_ty], - true)); - - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - - let partial_cmp_def = MethodDef { - name: "partial_cmp", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![borrowed_self()], - ret_ty: ret_ty, - attributes: attrs, - combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr) - })) - }; - - let trait_def = TraitDef { - span: span, - attributes: vec![], - path: path_std!(cx, core::cmp::PartialOrd), - additional_bounds: vec![], - generics: LifetimeBounds::empty(), - methods: vec![ - partial_cmp_def, - md!("lt", true, false), - md!("le", true, true), - md!("gt", false, false), - md!("ge", false, true) - ], + ), associated_types: Vec::new(), }; + trait_def.expand(cx, mitem, item, push) } -#[derive(Copy, Clone)] -pub enum OrderingOp { - PartialCmpOp, LtOp, LeOp, GtOp, GeOp, -} -pub fn some_ordering_collapsed(cx: &mut ExtCtxt, - span: Span, - op: OrderingOp, - self_arg_tags: &[ast::Ident]) -> P { +pub fn ordering_collapsed(cx: &mut ExtCtxt, + span: Span, + self_arg_tags: &[ast::Ident]) -> P { let lft = cx.expr_ident(span, self_arg_tags[0]); let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); - let op_str = match op { - PartialCmpOp => "partial_cmp", - LtOp => "lt", LeOp => "le", - GtOp => "gt", GeOp => "ge", - }; - cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt]) + cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt]) } -pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, +pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { let test_id = cx.ident_of("__test"); - let ordering = cx.path_global(span, - vec!(cx.ident_of_std("core"), - cx.ident_of("cmp"), - cx.ident_of("Ordering"), - cx.ident_of("Equal"))); - let ordering = cx.expr_path(ordering); - let equals_expr = cx.expr_some(span, ordering); + let equals_path = cx.path_global(span, + vec!(cx.ident_of_std("core"), + cx.ident_of("cmp"), + cx.ident_of("Ordering"), + cx.ident_of("Equal"))); - let partial_cmp_path = vec![ + let cmp_path = vec![ cx.ident_of_std("core"), cx.ident_of("cmp"), - cx.ident_of("PartialOrd"), - cx.ident_of("partial_cmp"), + cx.ident_of("Ord"), + cx.ident_of("cmp"), ]; /* Builds: - let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1); - if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { - let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2); - if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { + let __test = ::std::cmp::Ord::cmp(&self_field1, &other_field1); + if other == ::std::cmp::Ordering::Equal { + let __test = ::std::cmp::Ord::cmp(&self_field2, &other_field2); + if __test == ::std::cmp::Ordering::Equal { ... } else { __test @@ -144,7 +100,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, false, |cx, span, old, self_f, other_fs| { // let __test = new; - // if __test == Some(::std::cmp::Ordering::Equal) { + // if __test == ::std::cmp::Ordering::Equal { // old // } else { // __test @@ -161,77 +117,25 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, cx.expr_addr_of(span, other_f.clone()), ]; - cx.expr_call_global(span, partial_cmp_path.clone(), args) + cx.expr_call_global(span, cmp_path.clone(), args) }; let assign = cx.stmt_let(span, false, test_id, new); let cond = cx.expr_binary(span, ast::BiEq, cx.expr_ident(span, test_id), - equals_expr.clone()); + cx.expr_path(equals_path.clone())); let if_ = cx.expr_if(span, cond, old, Some(cx.expr_ident(span, test_id))); cx.expr_block(cx.block(span, vec!(assign), Some(if_))) }, - equals_expr.clone(), + cx.expr_path(equals_path.clone()), Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + cx.span_bug(span, "not exactly 2 arguments in `derives(Ord)`") } else { - some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple) - } - }), - cx, span, substr) -} - -/// Strict inequality. -fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, - span: Span, substr: &Substructure) -> P { - let op = if less {ast::BiLt} else {ast::BiGt}; - cs_fold( - false, // need foldr, - |cx, span, subexpr, self_f, other_fs| { - /* - build up a series of chain ||'s and &&'s from the inside - out (hence foldr) to get lexical ordering, i.e. for op == - `ast::lt` - - ``` - self.f1 < other.f1 || (!(other.f1 < self.f1) && - (self.f2 < other.f2 || (!(other.f2 < self.f2) && - (false) - )) - ) - ``` - - The optimiser should remove the redundancy. We explicitly - get use the binops to avoid auto-deref dereferencing too many - layers of pointers, if the type includes pointers. - */ - let other_f = match other_fs { - [ref o_f] => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - }; - - let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); - - let not_cmp = cx.expr_unary(span, ast::UnNot, - cx.expr_binary(span, op, other_f.clone(), self_f)); - - let and = cx.expr_binary(span, ast::BiAnd, not_cmp, subexpr); - cx.expr_binary(span, ast::BiOr, cmp, and) - }, - cx.expr_bool(span, equal), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - let op = match (less, equal) { - (true, true) => LeOp, (true, false) => LtOp, - (false, true) => GeOp, (false, false) => GtOp, - }; - some_ordering_collapsed(cx, span, op, tag_tuple) + ordering_collapsed(cx, span, tag_tuple) } }), cx, span, substr) diff --git a/src/libsyntax/ext/deriving/cmp/partial_eq.rs b/src/libsyntax/ext/deriving/cmp/partial_eq.rs new file mode 100644 index 0000000000000..db53ea63e539a --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/partial_eq.rs @@ -0,0 +1,95 @@ +// 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. + +use ast::{MetaItem, Item, Expr, self}; +use codemap::Span; +use ext::base::ExtCtxt; +use ext::build::AstBuilder; +use ext::deriving::generic::*; +use ext::deriving::generic::ty::*; +use parse::token::InternedString; +use ptr::P; + +pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: F) where + F: FnOnce(P), +{ + // structures are equal if all fields are equal, and non equal, if + // any fields are not equal or if the enum variants are different + fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { + cs_fold( + true, // use foldl + |cx, span, subexpr, self_f, other_fs| { + let other_f = match other_fs { + [ref o_f] => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") + }; + + let eq = cx.expr_binary(span, ast::BiEq, self_f, other_f.clone()); + + cx.expr_binary(span, ast::BiAnd, subexpr, eq) + }, + cx.expr_bool(span, true), + Box::new(|cx, span, _, _| cx.expr_bool(span, false)), + cx, span, substr) + } + fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { + cs_fold( + true, // use foldl + |cx, span, subexpr, self_f, other_fs| { + let other_f = match other_fs { + [ref o_f] => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") + }; + + let eq = cx.expr_binary(span, ast::BiNe, self_f, other_f.clone()); + + cx.expr_binary(span, ast::BiOr, subexpr, eq) + }, + cx.expr_bool(span, false), + Box::new(|cx, span, _, _| cx.expr_bool(span, true)), + cx, span, substr) + } + + macro_rules! md { + ($name:expr, $f:ident) => { { + let inline = cx.meta_word(span, InternedString::new("inline")); + let attrs = vec!(cx.attribute(span, inline)); + MethodDef { + name: $name, + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec!(borrowed_self()), + ret_ty: Literal(path_local!(bool)), + attributes: attrs, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + $f(a, b, c) + })) + } + } } + } + + let trait_def = TraitDef { + span: span, + attributes: Vec::new(), + path: path_std!(cx, core::cmp::PartialEq), + additional_bounds: Vec::new(), + generics: LifetimeBounds::empty(), + methods: vec!( + md!("eq", cs_eq), + md!("ne", cs_ne) + ), + associated_types: Vec::new(), + }; + trait_def.expand(cx, mitem, item, push) +} diff --git a/src/libsyntax/ext/deriving/cmp/partial_ord.rs b/src/libsyntax/ext/deriving/cmp/partial_ord.rs new file mode 100644 index 0000000000000..4e162d82bbf13 --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/partial_ord.rs @@ -0,0 +1,238 @@ +// 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. + +pub use self::OrderingOp::*; + +use ast; +use ast::{MetaItem, Item, Expr}; +use codemap::Span; +use ext::base::ExtCtxt; +use ext::build::AstBuilder; +use ext::deriving::generic::*; +use ext::deriving::generic::ty::*; +use parse::token::InternedString; +use ptr::P; + +pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: F) where + F: FnOnce(P), +{ + macro_rules! md { + ($name:expr, $op:expr, $equal:expr) => { { + let inline = cx.meta_word(span, InternedString::new("inline")); + let attrs = vec!(cx.attribute(span, inline)); + MethodDef { + name: $name, + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec!(borrowed_self()), + ret_ty: Literal(path_local!(bool)), + attributes: attrs, + combine_substructure: combine_substructure(Box::new(|cx, span, substr| { + cs_op($op, $equal, cx, span, substr) + })) + } + } } + } + + let ordering_ty = Literal(path_std!(cx, core::cmp::Ordering)); + let ret_ty = Literal(Path::new_(pathvec_std!(cx, core::option::Option), + None, + vec![box ordering_ty], + true)); + + let inline = cx.meta_word(span, InternedString::new("inline")); + let attrs = vec!(cx.attribute(span, inline)); + + let partial_cmp_def = MethodDef { + name: "partial_cmp", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec![borrowed_self()], + ret_ty: ret_ty, + attributes: attrs, + combine_substructure: combine_substructure(Box::new(|cx, span, substr| { + cs_partial_cmp(cx, span, substr) + })) + }; + + let trait_def = TraitDef { + span: span, + attributes: vec![], + path: path_std!(cx, core::cmp::PartialOrd), + additional_bounds: vec![], + generics: LifetimeBounds::empty(), + methods: vec![ + partial_cmp_def, + md!("lt", true, false), + md!("le", true, true), + md!("gt", false, false), + md!("ge", false, true) + ], + associated_types: Vec::new(), + }; + trait_def.expand(cx, mitem, item, push) +} + +#[derive(Copy, Clone)] +pub enum OrderingOp { + PartialCmpOp, LtOp, LeOp, GtOp, GeOp, +} + +pub fn some_ordering_collapsed(cx: &mut ExtCtxt, + span: Span, + op: OrderingOp, + self_arg_tags: &[ast::Ident]) -> P { + let lft = cx.expr_ident(span, self_arg_tags[0]); + let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); + let op_str = match op { + PartialCmpOp => "partial_cmp", + LtOp => "lt", LeOp => "le", + GtOp => "gt", GeOp => "ge", + }; + cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt]) +} + +pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, + substr: &Substructure) -> P { + let test_id = cx.ident_of("__test"); + let ordering = cx.path_global(span, + vec!(cx.ident_of_std("core"), + cx.ident_of("cmp"), + cx.ident_of("Ordering"), + cx.ident_of("Equal"))); + let ordering = cx.expr_path(ordering); + let equals_expr = cx.expr_some(span, ordering); + + let partial_cmp_path = vec![ + cx.ident_of_std("core"), + cx.ident_of("cmp"), + cx.ident_of("PartialOrd"), + cx.ident_of("partial_cmp"), + ]; + + /* + Builds: + + let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1); + if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { + let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2); + if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { + ... + } else { + __test + } + } else { + __test + } + + FIXME #6449: These `if`s could/should be `match`es. + */ + cs_fold( + // foldr nests the if-elses correctly, leaving the first field + // as the outermost one, and the last as the innermost. + false, + |cx, span, old, self_f, other_fs| { + // let __test = new; + // if __test == Some(::std::cmp::Ordering::Equal) { + // old + // } else { + // __test + // } + + let new = { + let other_f = match other_fs { + [ref o_f] => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), + }; + + let args = vec![ + cx.expr_addr_of(span, self_f), + cx.expr_addr_of(span, other_f.clone()), + ]; + + cx.expr_call_global(span, partial_cmp_path.clone(), args) + }; + + let assign = cx.stmt_let(span, false, test_id, new); + + let cond = cx.expr_binary(span, ast::BiEq, + cx.expr_ident(span, test_id), + equals_expr.clone()); + let if_ = cx.expr_if(span, + cond, + old, Some(cx.expr_ident(span, test_id))); + cx.expr_block(cx.block(span, vec!(assign), Some(if_))) + }, + equals_expr.clone(), + Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { + if self_args.len() != 2 { + cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + } else { + some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple) + } + }), + cx, span, substr) +} + +/// Strict inequality. +fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, + span: Span, substr: &Substructure) -> P { + let op = if less {ast::BiLt} else {ast::BiGt}; + cs_fold( + false, // need foldr, + |cx, span, subexpr, self_f, other_fs| { + /* + build up a series of chain ||'s and &&'s from the inside + out (hence foldr) to get lexical ordering, i.e. for op == + `ast::lt` + + ``` + self.f1 < other.f1 || (!(other.f1 < self.f1) && + (self.f2 < other.f2 || (!(other.f2 < self.f2) && + (false) + )) + ) + ``` + + The optimiser should remove the redundancy. We explicitly + get use the binops to avoid auto-deref dereferencing too many + layers of pointers, if the type includes pointers. + */ + let other_f = match other_fs { + [ref o_f] => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + }; + + let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); + + let not_cmp = cx.expr_unary(span, ast::UnNot, + cx.expr_binary(span, op, other_f.clone(), self_f)); + + let and = cx.expr_binary(span, ast::BiAnd, not_cmp, subexpr); + cx.expr_binary(span, ast::BiOr, cmp, and) + }, + cx.expr_bool(span, equal), + Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { + if self_args.len() != 2 { + cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + } else { + let op = match (less, equal) { + (true, true) => LeOp, (true, false) => LtOp, + (false, true) => GeOp, (false, false) => GtOp, + }; + some_ordering_collapsed(cx, span, op, tag_tuple) + } + }), + cx, span, substr) +} diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs deleted file mode 100644 index 83164d242e8fb..0000000000000 --- a/src/libsyntax/ext/deriving/cmp/totaleq.rs +++ /dev/null @@ -1,69 +0,0 @@ -// 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. - -use ast::{MetaItem, Item, Expr}; -use codemap::Span; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_totaleq(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), -{ - fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_same_method(|cx, span, exprs| { - // create `a.(); b.(); c.(); ...` - // (where method is `assert_receiver_is_total_eq`) - let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); - let block = cx.block(span, stmts, None); - cx.expr_block(block) - }, - Box::new(|cx, sp, _, _| { - cx.span_bug(sp, "non matching enums in derive(Eq)?") }), - cx, - span, - substr) - } - - let inline = cx.meta_word(span, InternedString::new("inline")); - let hidden = cx.meta_word(span, InternedString::new("hidden")); - let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden)); - let attrs = vec!(cx.attribute(span, inline), - cx.attribute(span, doc)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::cmp::Eq), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - methods: vec!( - MethodDef { - name: "assert_receiver_is_total_eq", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(), - ret_ty: nil_ty(), - attributes: attrs, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_total_eq_assert(a, b, c) - })) - } - ), - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs deleted file mode 100644 index 1de955856e712..0000000000000 --- a/src/libsyntax/ext/deriving/cmp/totalord.rs +++ /dev/null @@ -1,142 +0,0 @@ -// 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. - -use ast; -use ast::{MetaItem, Item, Expr}; -use codemap::Span; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use parse::token::InternedString; -use ptr::P; - -pub fn expand_deriving_totalord(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), -{ - let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path_std!(cx, core::cmp::Ord), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - methods: vec!( - MethodDef { - name: "cmp", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), - ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), - attributes: attrs, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_cmp(a, b, c) - })), - } - ), - associated_types: Vec::new(), - }; - - trait_def.expand(cx, mitem, item, push) -} - - -pub fn ordering_collapsed(cx: &mut ExtCtxt, - span: Span, - self_arg_tags: &[ast::Ident]) -> P { - let lft = cx.expr_ident(span, self_arg_tags[0]); - let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); - cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt]) -} - -pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P { - let test_id = cx.ident_of("__test"); - let equals_path = cx.path_global(span, - vec!(cx.ident_of_std("core"), - cx.ident_of("cmp"), - cx.ident_of("Ordering"), - cx.ident_of("Equal"))); - - let cmp_path = vec![ - cx.ident_of_std("core"), - cx.ident_of("cmp"), - cx.ident_of("Ord"), - cx.ident_of("cmp"), - ]; - - /* - Builds: - - let __test = ::std::cmp::Ord::cmp(&self_field1, &other_field1); - if other == ::std::cmp::Ordering::Equal { - let __test = ::std::cmp::Ord::cmp(&self_field2, &other_field2); - if __test == ::std::cmp::Ordering::Equal { - ... - } else { - __test - } - } else { - __test - } - - FIXME #6449: These `if`s could/should be `match`es. - */ - cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - |cx, span, old, self_f, other_fs| { - // let __test = new; - // if __test == ::std::cmp::Ordering::Equal { - // old - // } else { - // __test - // } - - let new = { - let other_f = match other_fs { - [ref o_f] => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), - }; - - let args = vec![ - cx.expr_addr_of(span, self_f), - cx.expr_addr_of(span, other_f.clone()), - ]; - - cx.expr_call_global(span, cmp_path.clone(), args) - }; - - let assign = cx.stmt_let(span, false, test_id, new); - - let cond = cx.expr_binary(span, ast::BiEq, - cx.expr_ident(span, test_id), - cx.expr_path(equals_path.clone())); - let if_ = cx.expr_if(span, - cond, - old, Some(cx.expr_ident(span, test_id))); - cx.expr_block(cx.block(span, vec!(assign), Some(if_))) - }, - cx.expr_path(equals_path.clone()), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derives(Ord)`") - } else { - ordering_collapsed(cx, span, tag_tuple) - } - }), - cx, span, substr) -} diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index d8c50b5a0942a..2222374a13573 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -66,14 +66,14 @@ pub mod show; pub mod default; pub mod primitive; +#[path="cmp/partial_eq.rs"] +pub mod partial_eq; #[path="cmp/eq.rs"] pub mod eq; -#[path="cmp/totaleq.rs"] -pub mod totaleq; +#[path="cmp/partial_ord.rs"] +pub mod partial_ord; #[path="cmp/ord.rs"] pub mod ord; -#[path="cmp/totalord.rs"] -pub mod totalord; pub mod generic; @@ -163,10 +163,10 @@ derive_traits! { "RustcDecodable" => decodable::expand_deriving_rustc_decodable, - "PartialEq" => eq::expand_deriving_eq, - "Eq" => totaleq::expand_deriving_totaleq, - "PartialOrd" => ord::expand_deriving_ord, - "Ord" => totalord::expand_deriving_totalord, + "PartialEq" => partial_eq::expand_deriving_partial_eq, + "Eq" => eq::expand_deriving_eq, + "PartialOrd" => partial_ord::expand_deriving_partial_ord, + "Ord" => ord::expand_deriving_ord, "Rand" => rand::expand_deriving_rand, From 0dff8914058f1e15b1e77c2f12ff3d9d8733a698 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Thu, 26 Mar 2015 18:07:49 -0700 Subject: [PATCH 2/9] syntax: Change deriving methods to take a `&mut FnMut(P)` This allows #[derive(...)]` to create more than one impl --- src/libsyntax/ext/deriving/bounds.rs | 24 ++++++------- src/libsyntax/ext/deriving/clone.rs | 11 +++--- src/libsyntax/ext/deriving/cmp/eq.rs | 11 +++--- src/libsyntax/ext/deriving/cmp/ord.rs | 11 +++--- src/libsyntax/ext/deriving/cmp/partial_eq.rs | 11 +++--- src/libsyntax/ext/deriving/cmp/partial_ord.rs | 11 +++--- src/libsyntax/ext/deriving/decodable.rs | 35 +++++++++---------- src/libsyntax/ext/deriving/default.rs | 11 +++--- src/libsyntax/ext/deriving/encodable.rs | 35 +++++++++---------- src/libsyntax/ext/deriving/generic/mod.rs | 11 +++--- src/libsyntax/ext/deriving/hash.rs | 11 +++--- src/libsyntax/ext/deriving/mod.rs | 8 ++--- src/libsyntax/ext/deriving/primitive.rs | 11 +++--- src/libsyntax/ext/deriving/rand.rs | 11 +++--- src/libsyntax/ext/deriving/show.rs | 11 +++--- 15 files changed, 102 insertions(+), 121 deletions(-) diff --git a/src/libsyntax/ext/deriving/bounds.rs b/src/libsyntax/ext/deriving/bounds.rs index e408c99935d1c..eb3debeac9901 100644 --- a/src/libsyntax/ext/deriving/bounds.rs +++ b/src/libsyntax/ext/deriving/bounds.rs @@ -15,22 +15,20 @@ use ext::deriving::generic::*; use ext::deriving::generic::ty::*; use ptr::P; -pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt, - span: Span, - _: &MetaItem, - _: &Item, - _: F) where - F: FnOnce(P), +pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt, + span: Span, + _: &MetaItem, + _: &Item, + _: &mut FnMut(P)) { cx.span_err(span, "this unsafe trait should be implemented explicitly"); } -pub fn expand_deriving_copy(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_copy(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { let path = Path::new(vec![ if cx.use_std { "std" } else { "core" }, @@ -48,5 +46,5 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt, associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, item, push); } diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index f89f3ab55f3f9..b6922d1bb32fe 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -17,12 +17,11 @@ use ext::deriving::generic::ty::*; use parse::token::InternedString; use ptr::P; -pub fn expand_deriving_clone(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_clone(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { let inline = cx.meta_word(span, InternedString::new("inline")); let attrs = vec!(cx.attribute(span, inline)); diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index 6418450685e39..6f4811976567c 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -17,12 +17,11 @@ use ext::deriving::generic::ty::*; use parse::token::InternedString; use ptr::P; -pub fn expand_deriving_eq(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_eq(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { cs_same_method(|cx, span, exprs| { diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index 1de955856e712..b2a4ef1dafbc8 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -18,12 +18,11 @@ use ext::deriving::generic::ty::*; use parse::token::InternedString; use ptr::P; -pub fn expand_deriving_totalord(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_ord(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { let inline = cx.meta_word(span, InternedString::new("inline")); let attrs = vec!(cx.attribute(span, inline)); diff --git a/src/libsyntax/ext/deriving/cmp/partial_eq.rs b/src/libsyntax/ext/deriving/cmp/partial_eq.rs index db53ea63e539a..f02e5ee14126d 100644 --- a/src/libsyntax/ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax/ext/deriving/cmp/partial_eq.rs @@ -17,12 +17,11 @@ use ext::deriving::generic::ty::*; use parse::token::InternedString; use ptr::P; -pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { // structures are equal if all fields are equal, and non equal, if // any fields are not equal or if the enum variants are different diff --git a/src/libsyntax/ext/deriving/cmp/partial_ord.rs b/src/libsyntax/ext/deriving/cmp/partial_ord.rs index 4e162d82bbf13..9da2db25f7ea2 100644 --- a/src/libsyntax/ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax/ext/deriving/cmp/partial_ord.rs @@ -20,12 +20,11 @@ use ext::deriving::generic::ty::*; use parse::token::InternedString; use ptr::P; -pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { macro_rules! md { ($name:expr, $op:expr, $equal:expr) => { { diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 6ce68948e4b01..14f0004101c81 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -21,33 +21,30 @@ use parse::token::InternedString; use parse::token; use ptr::P; -pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize") } -pub fn expand_deriving_decodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_decodable(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize") } -fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F, - krate: &'static str) where - F: FnOnce(P), +fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P), + krate: &'static str) { if !cx.use_std { // FIXME(#21880): lift this requirement. diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs index f9991a233547c..f04eaa08dead1 100644 --- a/src/libsyntax/ext/deriving/default.rs +++ b/src/libsyntax/ext/deriving/default.rs @@ -17,12 +17,11 @@ use ext::deriving::generic::ty::*; use parse::token::InternedString; use ptr::P; -pub fn expand_deriving_default(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_default(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { let inline = cx.meta_word(span, InternedString::new("inline")); let attrs = vec!(cx.attribute(span, inline)); diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 06255f4677925..877a90714d9e0 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -97,33 +97,30 @@ use ext::deriving::generic::ty::*; use parse::token; use ptr::P; -pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize") } -pub fn expand_deriving_encodable(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_encodable(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize") } -fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F, - krate: &'static str) where - F: FnOnce(P), +fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P), + krate: &'static str) { if !cx.use_std { // FIXME(#21880): lift this requirement. diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 397775fdbfec3..c685ca7412fc4 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -374,12 +374,11 @@ fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec TraitDef<'a> { - pub fn expand(&self, - cx: &mut ExtCtxt, - mitem: &ast::MetaItem, - item: &ast::Item, - push: F) where - F: FnOnce(P), + pub fn expand(&self, + cx: &mut ExtCtxt, + mitem: &ast::MetaItem, + item: &ast::Item, + push: &mut FnMut(P)) { let newitem = match item.node { ast::ItemStruct(ref struct_def, ref generics) => { diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index da80c7a0e6d15..2f6734b1a1433 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -16,12 +16,11 @@ use ext::deriving::generic::*; use ext::deriving::generic::ty::*; use ptr::P; -pub fn expand_deriving_hash(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_hash(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 2222374a13573..f7a32f4d20361 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -119,7 +119,7 @@ fn expand_derive(cx: &mut ExtCtxt, } macro_rules! derive_traits { - ($( $name:expr => $func:path, )*) => { + ($( $name:expr => $func:path, )+) => { pub fn register_all(env: &mut SyntaxEnv) { // Define the #[derive_*] extensions. $({ @@ -133,13 +133,13 @@ macro_rules! derive_traits { item: &Item, push: &mut FnMut(P)) { warn_if_deprecated(ecx, sp, $name); - $func(ecx, sp, mitem, item, |i| push(i)); + $func(ecx, sp, mitem, item, push); } } env.insert(intern(concat!("derive_", $name)), Decorator(Box::new(DeriveExtension))); - })* + })+ env.insert(intern("derive"), Modifier(Box::new(expand_derive))); @@ -147,7 +147,7 @@ macro_rules! derive_traits { fn is_builtin_trait(name: &str) -> bool { match name { - $( $name )|* => true, + $( $name )|+ => true, _ => false, } } diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index b2d0a9f6b51ad..625f759fcedf8 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -18,12 +18,11 @@ use ext::deriving::generic::ty::*; use parse::token::InternedString; use ptr::P; -pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { let inline = cx.meta_word(span, InternedString::new("inline")); let attrs = vec!(cx.attribute(span, inline)); diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 631e5f979d9ee..1f9bf728a4000 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -17,12 +17,11 @@ use ext::deriving::generic::*; use ext::deriving::generic::ty::*; use ptr::P; -pub fn expand_deriving_rand(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_rand(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { cx.span_warn(span, "`#[derive(Rand)]` is deprecated in favour of `#[derive_Rand]` from \ diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs index ae9a402006095..f3b0e8a768126 100644 --- a/src/libsyntax/ext/deriving/show.rs +++ b/src/libsyntax/ext/deriving/show.rs @@ -18,12 +18,11 @@ use ext::deriving::generic::ty::*; use parse::token; use ptr::P; -pub fn expand_deriving_show(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), +pub fn expand_deriving_show(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { // &mut ::std::fmt::Formatter let fmtr = Ptr(box Literal(path_std!(cx, core::fmt::Formatter)), From d1cb3b3b225a2520814faf1782fb1637d92034c1 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 31 Mar 2015 11:07:46 -0700 Subject: [PATCH 3/9] test: PadOnLeft was never used --- src/libtest/lib.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index c84703b93ed26..5c0b2a7fd1458 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -122,7 +122,6 @@ impl fmt::Display for TestName { #[derive(Clone, Copy)] enum NamePadding { PadNone, - PadOnLeft, PadOnRight, } @@ -130,13 +129,9 @@ impl TestDesc { fn padded_name(&self, column_count: usize, align: NamePadding) -> String { let mut name = String::from_str(self.name.as_slice()); let fill = column_count.saturating_sub(name.len()); - let mut pad = repeat(" ").take(fill).collect::(); + let pad = repeat(" ").take(fill).collect::(); match align { PadNone => name, - PadOnLeft => { - pad.push_str(&name); - pad - } PadOnRight => { name.push_str(&pad); name @@ -690,7 +685,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec ) -> io::Res fn len_if_padded(t: &TestDescAndFn) -> usize { match t.testfn.padding() { PadNone => 0, - PadOnLeft | PadOnRight => t.desc.name.as_slice().len(), + PadOnRight => t.desc.name.as_slice().len(), } } match tests.iter().max_by(|t|len_if_padded(*t)) { From 02c5ff7d9d95a35d5ef5e3a825ea84708de07f60 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 1 Apr 2015 10:51:24 -0700 Subject: [PATCH 4/9] syntax: Clean up the indentation for #[derive(Eq)] --- src/libsyntax/ext/deriving/cmp/eq.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index 6f4811976567c..ce8f0a7b32b90 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -24,18 +24,20 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, push: &mut FnMut(P)) { fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_same_method(|cx, span, exprs| { - // create `a.(); b.(); c.(); ...` - // (where method is `assert_receiver_is_total_eq`) - let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); - let block = cx.block(span, stmts, None); - cx.expr_block(block) - }, - Box::new(|cx, sp, _, _| { - cx.span_bug(sp, "non matching enums in derive(Eq)?") }), - cx, - span, - substr) + cs_same_method( + |cx, span, exprs| { + // create `a.(); b.(); c.(); ...` + // (where method is `assert_receiver_is_total_eq`) + let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); + let block = cx.block(span, stmts, None); + cx.expr_block(block) + }, + Box::new(|cx, sp, _, _| { + cx.span_bug(sp, "non matching enums in derive(Eq)?") }), + cx, + span, + substr + ) } let inline = cx.meta_word(span, InternedString::new("inline")); From 214113a6c8bf4eab2d068dec6a7f16254c283d63 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 31 Mar 2015 14:37:20 -0700 Subject: [PATCH 5/9] syntax: Make #[derive(Copy)] imply #[derive(Clone)] --- src/libcore/fmt/mod.rs | 2 + src/liblibc/lib.rs | 3 + src/librand/isaac.rs | 2 + src/librustc/middle/liveness.rs | 1 + src/librustc_borrowck/borrowck/move_data.rs | 1 + src/libstd/net/addr.rs | 3 + src/libstd/net/ip.rs | 2 + src/libsyntax/ast_map/mod.rs | 1 + src/libsyntax/ext/deriving/bounds.rs | 117 ++++++++++++++++++-- src/libsyntax/ext/deriving/mod.rs | 18 +++ 10 files changed, 141 insertions(+), 9 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index be804327663e5..37f45fc815723 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -14,6 +14,7 @@ use cell::{Cell, RefCell, Ref, RefMut, BorrowState}; use char::CharExt; +#[cfg(stage0)] use clone::Clone; use iter::Iterator; use marker::{Copy, PhantomData, Sized}; @@ -141,6 +142,7 @@ pub struct ArgumentV1<'a> { formatter: fn(&Void, &mut Formatter) -> Result, } +#[cfg(stage0)] impl<'a> Clone for ArgumentV1<'a> { fn clone(&self) -> ArgumentV1<'a> { *self diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 44d689059d1cf..d9d9345f77045 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -2091,6 +2091,7 @@ pub mod types { pub __ss_align: i64, pub __ss_pad2: [u8; 112], } + #[cfg(stage0)] impl ::core::clone::Clone for sockaddr_storage { fn clone(&self) -> sockaddr_storage { *self } } @@ -2154,6 +2155,7 @@ pub mod types { pub sun_family: sa_family_t, pub sun_path: [c_char; 104] } + #[cfg(stage0)] impl ::core::clone::Clone for sockaddr_un { fn clone(&self) -> sockaddr_un { *self } } @@ -2369,6 +2371,7 @@ pub mod types { pub __sig: c_long, pub __opaque: [c_char; 56] } + #[cfg(stage0)] impl ::core::clone::Clone for pthread_attr_t { fn clone(&self) -> pthread_attr_t { *self } } diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index a7f7889783f70..cd1673696447f 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -187,6 +187,7 @@ impl IsaacRng { } // Cannot be derived because [u32; 256] does not implement Clone +#[cfg(stage0)] impl Clone for IsaacRng { fn clone(&self) -> IsaacRng { *self @@ -432,6 +433,7 @@ impl Isaac64Rng { } // Cannot be derived because [u32; 256] does not implement Clone +#[cfg(stage0)] impl Clone for Isaac64Rng { fn clone(&self) -> Isaac64Rng { *self diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index d7161607b61eb..f8e9ff876975f 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -153,6 +153,7 @@ impl LiveNode { fn get(&self) -> usize { let LiveNode(v) = *self; v } } +#[cfg(stage0)] impl Clone for LiveNode { fn clone(&self) -> LiveNode { LiveNode(self.get()) diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 2d1b57243d1cc..312965b59fa72 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -84,6 +84,7 @@ impl MovePathIndex { } } +#[cfg(stage0)] impl Clone for MovePathIndex { fn clone(&self) -> MovePathIndex { MovePathIndex(self.get()) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 886f252fb1926..8061c9d691333 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -206,10 +206,13 @@ impl fmt::Debug for SocketAddrV6 { } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for SocketAddrV4 { fn clone(&self) -> SocketAddrV4 { *self } } + +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for SocketAddrV6 { fn clone(&self) -> SocketAddrV6 { *self } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index c8b1928747705..35e98ba9ef7b5 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -174,6 +174,7 @@ impl fmt::Debug for Ipv4Addr { } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Ipv4Addr { fn clone(&self) -> Ipv4Addr { *self } @@ -417,6 +418,7 @@ impl fmt::Debug for Ipv6Addr { } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Ipv6Addr { fn clone(&self) -> Ipv6Addr { *self } diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 2a9a609ecd1e9..5806dc4c3754e 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -148,6 +148,7 @@ enum MapEntry<'ast> { RootInlinedParent(&'ast InlinedParent) } +#[cfg(stage0)] impl<'ast> Clone for MapEntry<'ast> { fn clone(&self) -> MapEntry<'ast> { *self diff --git a/src/libsyntax/ext/deriving/bounds.rs b/src/libsyntax/ext/deriving/bounds.rs index eb3debeac9901..9437091d50f23 100644 --- a/src/libsyntax/ext/deriving/bounds.rs +++ b/src/libsyntax/ext/deriving/bounds.rs @@ -8,13 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{MetaItem, Item}; -use codemap::Span; +use abi; +use ast::{self, MetaItem, Item}; +use codemap::{Span, respan}; use ext::base::ExtCtxt; +use ext::build::AstBuilder; use ext::deriving::generic::*; use ext::deriving::generic::ty::*; +use owned_slice::OwnedSlice; +use parse::token::{InternedString, special_idents}; use ptr::P; +use super::clone; + pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt, span: Span, _: &MetaItem, @@ -30,16 +36,10 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt, item: &Item, push: &mut FnMut(P)) { - let path = Path::new(vec![ - if cx.use_std { "std" } else { "core" }, - "marker", - "Copy", - ]); - let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: path, + path: path_std!(cx, core::marker::Copy), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), methods: Vec::new(), @@ -47,4 +47,103 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt, }; trait_def.expand(cx, mitem, item, push); + + expand_deriving_clone_when_copy(cx, span, mitem, item, push) +} + +fn expand_deriving_clone_when_copy(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) +{ + // For generic types we need to destructure our value in order to recursively call clone. + // However, as an optimization for non-generic types, we can just generate: + // + // impl<...> Clone for $ty { + // fn clone(&self) -> Self { *self } + // } + // + // But the generic deriving helpers do not support generating such a simple method. So we'll + // build this method by hand. However, we want to take advantage of generic deriving generating + // the `Generics` for us. So we'll generate an empty impl, then later on add our method. It's + // not pretty, but it works until we get a more general purpose ast builder. + match item.node { + ast::ItemStruct(_, ref generics) | ast::ItemEnum(_, ref generics) => { + if generics.is_type_parameterized() { + clone::expand_deriving_clone(cx, span, mitem, item, push); + return; + } + } + _ => { + cx.span_err(mitem.span, "`derive` may only be applied to structs and enums"); + return; + } + } + + let trait_def = TraitDef { + span: span, + attributes: Vec::new(), + path: path_std!(cx, core::clone::Clone), + additional_bounds: Vec::new(), + generics: LifetimeBounds::empty(), + methods: Vec::new(), + associated_types: Vec::new(), + }; + + // We want to use the `cx` to build our ast, but it's passed by `&mut` to the expand method. So + // we'll extract out the generated item by way of an option. + let mut expanded_item = None; + + trait_def.expand(cx, mitem, item, &mut |item: P| { + expanded_item = Some(item); + }); + + let expanded_item = expanded_item.unwrap().map(|mut item| { + match item.node { + ast::ItemImpl(_, _, _, _, ref ty, ref mut impl_items) => { + let self_arg = ast::Arg::new_self(span, ast::MutImmutable, special_idents::self_); + let decl = cx.fn_decl(vec![self_arg], ty.clone()); + + let sig = ast::MethodSig { + unsafety: ast::Unsafety::Normal, + abi: abi::Rust, + decl: decl.clone(), + generics: ast::Generics { + lifetimes: Vec::new(), + ty_params: OwnedSlice::empty(), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: Vec::new(), + } + }, + explicit_self: respan( + span, + ast::SelfRegion(None, ast::MutImmutable, cx.ident_of("self")), + ), + }; + + let block = cx.block_expr(cx.expr_deref(span, cx.expr_self(span))); + + let inline = cx.meta_word(span, InternedString::new("inline")); + let attrs = vec!(cx.attribute(span, inline)); + + impl_items.push(P(ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: cx.ident_of("clone"), + vis: ast::Visibility::Inherited, + attrs: attrs, + node: ast::ImplItem_::MethodImplItem(sig, block), + span: span, + })); + } + _ => { + cx.span_bug(span, "we should have gotten an impl") + } + }; + + item + }); + + push(expanded_item) } diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index f7a32f4d20361..cd94f6b5335bf 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -92,6 +92,21 @@ fn expand_derive(cx: &mut ExtCtxt, cx.span_warn(mitem.span, "empty trait list in `derive`"); } + // FIXME: This can be removed after a snapshot + let mut seen_copy = false; + + for titem in traits.iter() { + match titem.node { + MetaWord(ref tname) => { + match &**tname { + "Copy" => { seen_copy = true; } + _ => { } + } + } + _ => { } + } + } + for titem in traits.iter().rev() { let tname = match titem.node { MetaWord(ref tname) => tname, @@ -109,6 +124,9 @@ fn expand_derive(cx: &mut ExtCtxt, continue; } + // FIXME: This can be removed after a snapshot + if seen_copy && &**tname == "Clone" { continue; } + // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span, intern_and_get_ident(&format!("derive_{}", tname))))); From f5b939a26f8e40bfa1efccee7ce415c2056cd67a Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 31 Mar 2015 14:38:21 -0700 Subject: [PATCH 6/9] syntax: Change #[derive(Eq)] imply #[derive(PartialEq)] --- src/libcollections/string.rs | 1 + src/librustc/middle/ty.rs | 4 +++- src/librustc_borrowck/borrowck/mod.rs | 5 ++++- src/libstd/path.rs | 5 ++++- src/libsyntax/ast.rs | 8 ++++++-- src/libsyntax/ext/deriving/cmp/eq.rs | 7 ++++++- src/libsyntax/ext/deriving/mod.rs | 3 +++ 7 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 7a7725320914f..d98d6c27885ea 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -793,6 +793,7 @@ impl<'a, 'b> Pattern<'a> for &'b String { } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for String { #[inline] diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 1123c9236312a..cf8f9a1da1342 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1708,7 +1708,7 @@ pub enum UnconstrainedNumeric { } -#[derive(Clone, RustcEncodable, RustcDecodable, Eq, Hash, Debug, Copy)] +#[derive(Clone, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum InferRegion { ReVar(RegionVid), ReSkolemized(u32, BoundRegion) @@ -1731,6 +1731,8 @@ impl cmp::PartialEq for InferRegion { } } +impl cmp::Eq for InferRegion {} + impl fmt::Debug for TyVid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{ write!(f, "_#{}t", self.index) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f8da075e4bdc2..d8a455f6e546c 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -278,7 +278,7 @@ impl<'tcx> Loan<'tcx> { } } -#[derive(Eq, Hash, Debug)] +#[derive(Hash, Debug)] pub struct LoanPath<'tcx> { kind: LoanPathKind<'tcx>, ty: ty::Ty<'tcx>, @@ -293,6 +293,9 @@ impl<'tcx> PartialEq for LoanPath<'tcx> { } } +impl<'tcx> Eq for LoanPath<'tcx> {} + + #[derive(PartialEq, Eq, Hash, Debug)] pub enum LoanPathKind<'tcx> { LpVar(ast::NodeId), // `x` in README.md diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 4471b5afa84c8..377371809b592 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -449,7 +449,7 @@ enum State { /// /// Does not occur on Unix. #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Copy, Clone, Eq, Hash, Debug)] +#[derive(Copy, Clone, Hash, Debug)] pub struct PrefixComponent<'a> { /// The prefix as an unparsed `OsStr` slice. raw: &'a OsStr, @@ -472,6 +472,9 @@ impl<'a> PrefixComponent<'a> { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> cmp::Eq for PrefixComponent<'a> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> cmp::PartialEq for PrefixComponent<'a> { fn eq(&self, other: &PrefixComponent<'a>) -> bool { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 40390765dde84..9eede6d502f82 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -78,7 +78,7 @@ use serialize::{Encodable, Decodable, Encoder, Decoder}; /// table) and a SyntaxContext to track renaming and /// macro expansion per Flatt et al., "Macros /// That Work Together" -#[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)] +#[derive(Clone, Copy, Hash, PartialOrd, Ord)] pub struct Ident { pub name: Name, pub ctxt: SyntaxContext @@ -149,6 +149,8 @@ impl PartialEq for Ident { } } +impl Eq for Ident {} + /// A SyntaxContext represents a chain of macro-expandings /// and renamings. Each macro expansion corresponds to /// a fresh u32 @@ -502,7 +504,7 @@ pub struct Crate { pub type MetaItem = Spanned; -#[derive(Clone, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum MetaItem_ { MetaWord(InternedString), MetaList(InternedString, Vec>), @@ -534,6 +536,8 @@ impl PartialEq for MetaItem_ { } } +impl Eq for MetaItem_ {} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Block { /// Statements in a block diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index ce8f0a7b32b90..37cc7c886c1c0 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -17,6 +17,8 @@ use ext::deriving::generic::ty::*; use parse::token::InternedString; use ptr::P; +use super::partial_eq; + pub fn expand_deriving_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, @@ -66,5 +68,8 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, ), associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + + trait_def.expand(cx, mitem, item, push); + + partial_eq::expand_deriving_partial_eq(cx, span, mitem, item, push) } diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index cd94f6b5335bf..6bb39646a09d3 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -94,12 +94,14 @@ fn expand_derive(cx: &mut ExtCtxt, // FIXME: This can be removed after a snapshot let mut seen_copy = false; + let mut seen_eq = false; for titem in traits.iter() { match titem.node { MetaWord(ref tname) => { match &**tname { "Copy" => { seen_copy = true; } + "Eq" => { seen_eq = true; } _ => { } } } @@ -126,6 +128,7 @@ fn expand_derive(cx: &mut ExtCtxt, // FIXME: This can be removed after a snapshot if seen_copy && &**tname == "Clone" { continue; } + if seen_eq && &**tname == "PartialEq" { continue; } // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span, From 6dbb0efdb9c6a0af53a6ba4dd2133fa7e7e13d50 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 31 Mar 2015 14:38:45 -0700 Subject: [PATCH 7/9] syntax: Make #[derive(Ord)] imply #[derive(PartialOrd)] --- src/libsyntax/ext/deriving/cmp/ord.rs | 6 +++++- src/libsyntax/ext/deriving/mod.rs | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index b2a4ef1dafbc8..96fa5d6dce009 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -18,6 +18,8 @@ use ext::deriving::generic::ty::*; use parse::token::InternedString; use ptr::P; +use super::partial_ord; + pub fn expand_deriving_ord(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, @@ -48,7 +50,9 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, item, push); + + partial_ord::expand_deriving_partial_ord(cx, span, mitem, item, push) } diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 6bb39646a09d3..dede60b5ba0e1 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -95,6 +95,7 @@ fn expand_derive(cx: &mut ExtCtxt, // FIXME: This can be removed after a snapshot let mut seen_copy = false; let mut seen_eq = false; + let mut seen_ord = false; for titem in traits.iter() { match titem.node { @@ -102,6 +103,7 @@ fn expand_derive(cx: &mut ExtCtxt, match &**tname { "Copy" => { seen_copy = true; } "Eq" => { seen_eq = true; } + "Ord" => { seen_ord = true; } _ => { } } } @@ -129,6 +131,7 @@ fn expand_derive(cx: &mut ExtCtxt, // FIXME: This can be removed after a snapshot if seen_copy && &**tname == "Clone" { continue; } if seen_eq && &**tname == "PartialEq" { continue; } + if seen_ord && &**tname == "PartialOrd" { continue; } // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span, From eed443b25c8b52c2ab45c777b50c180d7db6b414 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 1 Apr 2015 10:45:26 -0700 Subject: [PATCH 8/9] syntax: Shrink the impl PartialOrd with #[derive(Ord)] This PR generates a simplified `PartialOrd` implementation when the type is `Ord` and non-generic. It produces essentially: impl ::std::cmp::PartialOrd for $ty { fn partial_cmp(&self, other: &$ty) -> Option { Some(::std::cmp::Ord::cmp(self, other)) } } --- src/libsyntax/ext/deriving/cmp/ord.rs | 153 +++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index 96fa5d6dce009..eb97fa6da8ba9 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -8,14 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use abi; use ast; use ast::{MetaItem, Item, Expr}; -use codemap::Span; +use codemap::{Span, respan}; use ext::base::ExtCtxt; use ext::build::AstBuilder; use ext::deriving::generic::*; use ext::deriving::generic::ty::*; -use parse::token::InternedString; +use owned_slice::OwnedSlice; +use parse::token::{InternedString, special_idents}; use ptr::P; use super::partial_ord; @@ -52,7 +54,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, trait_def.expand(cx, mitem, item, push); - partial_ord::expand_deriving_partial_ord(cx, span, mitem, item, push) + expand_deriving_partial_ord_when_ord(cx, span, mitem, item, push) } @@ -143,3 +145,148 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, }), cx, span, substr) } + +fn expand_deriving_partial_ord_when_ord(cx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Item, + push: &mut FnMut(P)) { + // For generic types we need to destructure our value in order to recursively call clone. + // However, as an optimization for non-generic types, we can just generate: + // + // impl<...> PartialOrd for $ty { + // fn partial_cmp(&self, other: &$ty) -> Self { self.cmp(other) } + // } + // + // But the generic deriving helpers do not support generating such a simple method. So we'll + // build this method by hand. However, we want to take advantage of generic deriving generating + // the `Generics` for us. So we'll generate an empty impl, then later on add our method. It's + // not pretty, but it works until we get a more general purpose ast builder. + match item.node { + ast::ItemStruct(_, ref generics) | ast::ItemEnum(_, ref generics) => { + if generics.is_type_parameterized() { + partial_ord::expand_deriving_partial_ord(cx, span, mitem, item, push); + return; + } + } + _ => { + cx.span_err(mitem.span, "`derive` may only be applied to structs and enums"); + return; + } + } + + let trait_def = TraitDef { + span: span, + attributes: Vec::new(), + path: path_std!(cx, core::cmp::PartialOrd), + additional_bounds: Vec::new(), + generics: LifetimeBounds::empty(), + methods: Vec::new(), + associated_types: Vec::new(), + }; + + // We want to use the `cx` to build our ast, but it's passed by `&mut` to the expand method. So + // we'll extract out the generated item by way of an option. + let mut expanded_item = None; + + trait_def.expand(cx, mitem, item, &mut |item: P| { + expanded_item = Some(item); + }); + + let expanded_item = expanded_item.unwrap().map(|mut item| { + match item.node { + ast::ItemImpl(_, _, _, _, ref ty, ref mut impl_items) => { + let self_arg = ast::Arg::new_self(span, ast::MutImmutable, special_idents::self_); + let other_arg = cx.arg( + span, + cx.ident_of("other"), + cx.ty_rptr( + span, + ty.clone(), + None, + ast::Mutability::MutImmutable, + ), + ); + let decl = cx.fn_decl( + vec![self_arg, other_arg], + cx.ty_option( + cx.ty_path( + cx.path_global( + span, + vec![ + cx.ident_of_std("core"), + cx.ident_of("cmp"), + cx.ident_of("Ordering"), + ], + ) + ) + ) + ); + + let sig = ast::MethodSig { + unsafety: ast::Unsafety::Normal, + abi: abi::Rust, + decl: decl.clone(), + generics: ast::Generics { + lifetimes: Vec::new(), + ty_params: OwnedSlice::empty(), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: Vec::new(), + } + }, + explicit_self: respan( + span, + ast::SelfRegion(None, ast::MutImmutable, cx.ident_of("self")), + ), + }; + + let block = cx.block_expr( + cx.expr_some( + span, + cx.expr_call( + span, + cx.expr_path( + cx.path_global( + span, + vec![ + cx.ident_of_std("core"), + cx.ident_of("cmp"), + cx.ident_of("Ord"), + cx.ident_of("cmp"), + ], + ), + ), + vec![ + cx.expr_self(span), + cx.expr_addr_of( + span, + cx.expr_ident(span, cx.ident_of("other")) + ), + ] + ) + ) + ); + + let inline = cx.meta_word(span, InternedString::new("inline")); + let attrs = vec!(cx.attribute(span, inline)); + + impl_items.push(P(ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: cx.ident_of("partial_cmp"), + vis: ast::Visibility::Inherited, + attrs: attrs, + node: ast::ImplItem_::MethodImplItem(sig, block), + span: span, + })); + } + _ => { + cx.span_bug(span, "we should have gotten an impl") + } + }; + + item + }); + + push(expanded_item) +} From 6231cc0e488b35e13c786183f0a72ff78f604ab0 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 3 Apr 2015 12:10:37 -0400 Subject: [PATCH 9/9] syntax: Fix the #[derive(Ord)] doc about the derived PartialOrd --- src/libsyntax/ext/deriving/cmp/ord.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index eb97fa6da8ba9..9de53319bfbbd 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -155,7 +155,7 @@ fn expand_deriving_partial_ord_when_ord(cx: &mut ExtCtxt, // However, as an optimization for non-generic types, we can just generate: // // impl<...> PartialOrd for $ty { - // fn partial_cmp(&self, other: &$ty) -> Self { self.cmp(other) } + // fn partial_cmp(&self, other: &$ty) -> Option { Some(self.cmp(other)) } // } // // But the generic deriving helpers do not support generating such a simple method. So we'll