Skip to content

More flexible and robust deriving code #6267

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 59 additions & 25 deletions src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,43 +54,52 @@ pub fn mk_binary(cx: @ext_ctxt, sp: span, op: ast::binop,
cx.next_id(); // see ast_util::op_expr_callee_id
mk_expr(cx, sp, ast::expr_binary(op, lhs, rhs))
}

pub fn mk_deref(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
mk_unary(cx, sp, ast::deref, e)
}
pub fn mk_unary(cx: @ext_ctxt, sp: span, op: ast::unop, e: @ast::expr)
-> @ast::expr {
cx.next_id(); // see ast_util::op_expr_callee_id
mk_expr(cx, sp, ast::expr_unary(op, e))
}
pub fn mk_raw_path(sp: span, idents: ~[ast::ident]) -> @ast::Path {
mk_raw_path_(sp, idents, ~[])
mk_raw_path_(sp, idents, None, ~[])
}
pub fn mk_raw_path_(sp: span,
idents: ~[ast::ident],
rp: Option<@ast::Lifetime>,
types: ~[@ast::Ty])
-> @ast::Path {
@ast::Path { span: sp,
global: false,
idents: idents,
rp: None,
rp: rp,
types: types }
}
pub fn mk_raw_path_global(sp: span, idents: ~[ast::ident]) -> @ast::Path {
mk_raw_path_global_(sp, idents, ~[])
mk_raw_path_global_(sp, idents, None, ~[])
}
pub fn mk_raw_path_global_(sp: span,
idents: ~[ast::ident],
rp: Option<@ast::Lifetime>,
types: ~[@ast::Ty]) -> @ast::Path {
@ast::Path { span: sp,
global: true,
idents: idents,
rp: None,
rp: rp,
types: types }
}
pub fn mk_path_raw(cx: @ext_ctxt, sp: span, path: @ast::Path)-> @ast::expr {
mk_expr(cx, sp, ast::expr_path(path))
}
pub fn mk_path(cx: @ext_ctxt, sp: span, idents: ~[ast::ident])
-> @ast::expr {
mk_expr(cx, sp, ast::expr_path(mk_raw_path(sp, idents)))
mk_path_raw(cx, sp, mk_raw_path(sp, idents))
}
pub fn mk_path_global(cx: @ext_ctxt, sp: span, idents: ~[ast::ident])
-> @ast::expr {
mk_expr(cx, sp, ast::expr_path(mk_raw_path_global(sp, idents)))
mk_path_raw(cx, sp, mk_raw_path_global(sp, idents))
}
pub fn mk_access_(cx: @ext_ctxt, sp: span, p: @ast::expr, m: ast::ident)
-> @ast::expr {
Expand Down Expand Up @@ -354,44 +363,69 @@ pub fn mk_stmt(cx: @ext_ctxt, span: span, expr: @ast::expr) -> @ast::stmt {
let stmt_ = ast::stmt_semi(expr, cx.next_id());
@codemap::spanned { node: stmt_, span: span }
}

pub fn mk_ty_mt(ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt {
ast::mt {
ty: ty,
mutbl: mutbl
}
}

pub fn mk_ty(cx: @ext_ctxt,
span: span,
ty: ast::ty_) -> @ast::Ty {
@ast::Ty {
id: cx.next_id(),
span: span,
node: ty
}
}

pub fn mk_ty_path(cx: @ext_ctxt,
span: span,
idents: ~[ ast::ident ])
-> @ast::Ty {
let ty = build::mk_raw_path(span, idents);
let ty = ast::ty_path(ty, cx.next_id());
let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span };
ty
mk_ty_path_path(cx, span, ty)
}

pub fn mk_ty_path_global(cx: @ext_ctxt,
span: span,
idents: ~[ ast::ident ])
-> @ast::Ty {
let ty = build::mk_raw_path_global(span, idents);
let ty = ast::ty_path(ty, cx.next_id());
let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span };
ty
mk_ty_path_path(cx, span, ty)
}

pub fn mk_ty_path_path(cx: @ext_ctxt,
span: span,
path: @ast::Path)
-> @ast::Ty {
let ty = ast::ty_path(path, cx.next_id());
mk_ty(cx, span, ty)
}

pub fn mk_ty_rptr(cx: @ext_ctxt,
span: span,
ty: @ast::Ty,
lifetime: Option<@ast::Lifetime>,
mutbl: ast::mutability)
-> @ast::Ty {
@ast::Ty {
id: cx.next_id(),
span: span,
node: ast::ty_rptr(
None,
ast::mt { ty: ty, mutbl: mutbl }
),
}
mk_ty(cx, span,
ast::ty_rptr(lifetime, mk_ty_mt(ty, mutbl)))
}
pub fn mk_ty_uniq(cx: @ext_ctxt, span: span, ty: @ast::Ty) -> @ast::Ty {
mk_ty(cx, span, ast::ty_uniq(mk_ty_mt(ty, ast::m_imm)))
}
pub fn mk_ty_box(cx: @ext_ctxt, span: span,
ty: @ast::Ty, mutbl: ast::mutability) -> @ast::Ty {
mk_ty(cx, span, ast::ty_box(mk_ty_mt(ty, mutbl)))
}



pub fn mk_ty_infer(cx: @ext_ctxt, span: span) -> @ast::Ty {
@ast::Ty {
id: cx.next_id(),
node: ast::ty_infer,
span: span,
}
mk_ty(cx, span, ast::ty_infer)
}
pub fn mk_trait_ref_global(cx: @ext_ctxt,
span: span,
Expand Down
13 changes: 8 additions & 5 deletions src/libsyntax/ext/deriving/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use codemap::span;
use ext::base::ext_ctxt;
use ext::build;
use ext::deriving::generic::*;
use core::option::{None,Some};


pub fn expand_deriving_clone(cx: @ext_ctxt,
Expand All @@ -22,13 +21,16 @@ pub fn expand_deriving_clone(cx: @ext_ctxt,
in_items: ~[@item])
-> ~[@item] {
let trait_def = TraitDef {
path: ~[~"core", ~"clone", ~"Clone"],
path: Path::new(~[~"core", ~"clone", ~"Clone"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),
methods: ~[
MethodDef {
name: ~"clone",
nargs: 0,
output_type: None, // return Self
generics: LifetimeBounds::empty(),
self_ty: borrowed_explicit_self(),
args: ~[],
ret_ty: Self,
const_nonmatching: false,
combine_substructure: cs_clone
}
Expand Down Expand Up @@ -66,7 +68,8 @@ fn cs_clone(cx: @ext_ctxt, span: span,
ctor_ident = ~[ variant.node.name ];
all_fields = af;
},
EnumNonMatching(*) => cx.bug("Non-matching enum variants in `deriving(Clone)`")
EnumNonMatching(*) => cx.span_bug(span, "Non-matching enum variants in `deriving(Clone)`"),
StaticEnum(*) | StaticStruct(*) => cx.span_bug(span, "Static method in `deriving(Clone)`")
}

match all_fields {
Expand Down
19 changes: 10 additions & 9 deletions src/libsyntax/ext/deriving/cmp/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,45 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.


use ast::{meta_item, item, expr};
use codemap::span;
use ext::base::ext_ctxt;
use ext::build;
use ext::deriving::generic::*;

use core::option::Some;

pub fn expand_deriving_eq(cx: @ext_ctxt,
span: span,
mitem: @meta_item,
in_items: ~[@item]) -> ~[@item] {
// 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: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
cs_and(|cx, span, _| build::mk_bool(cx, span, false),
cs_and(|cx, span, _, _| build::mk_bool(cx, span, false),
cx, span, substr)
}
fn cs_ne(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
cs_or(|cx, span, _| build::mk_bool(cx, span, true),
cs_or(|cx, span, _, _| build::mk_bool(cx, span, true),
cx, span, substr)
}

macro_rules! md (
($name:expr, $f:ident) => {
MethodDef {
name: $name,
output_type: Some(~[~"bool"]),
nargs: 1,
generics: LifetimeBounds::empty(),
self_ty: borrowed_explicit_self(),
args: ~[borrowed_self()],
ret_ty: Literal(Path::new(~[~"bool"])),
const_nonmatching: true,
combine_substructure: $f
},
}
)
);

let trait_def = TraitDef {
path: ~[~"core", ~"cmp", ~"Eq"],
path: Path::new(~[~"core", ~"cmp", ~"Eq"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),
methods: ~[
md!(~"eq", cs_eq),
md!(~"ne", cs_ne)
Expand Down
42 changes: 23 additions & 19 deletions src/libsyntax/ext/deriving/cmp/ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,33 @@ use codemap::span;
use ext::base::ext_ctxt;
use ext::build;
use ext::deriving::generic::*;
use core::option::Some;

macro_rules! md {
($name:expr, $less:expr, $equal:expr) => {
MethodDef {
name: $name,
output_type: Some(~[~"bool"]),
nargs: 1,
const_nonmatching: false,
combine_substructure: |cx, span, substr|
cs_ord($less, $equal, cx, span, substr)
}
}
}

pub fn expand_deriving_ord(cx: @ext_ctxt,
span: span,
mitem: @meta_item,
in_items: ~[@item]) -> ~[@item] {
macro_rules! md (
($name:expr, $less:expr, $equal:expr) => {
MethodDef {
name: $name,
generics: LifetimeBounds::empty(),
self_ty: borrowed_explicit_self(),
args: ~[borrowed_self()],
ret_ty: Literal(Path::new(~[~"bool"])),
const_nonmatching: false,
combine_substructure: |cx, span, substr|
cs_ord($less, $equal, cx, span, substr)
}
}
);



let trait_def = TraitDef {
path: ~[~"core", ~"cmp", ~"Ord"],
path: Path::new(~[~"core", ~"cmp", ~"Ord"]),
// XXX: Ord doesn't imply Eq yet
additional_bounds: ~[~[~"core", ~"cmp", ~"Eq"]],
additional_bounds: ~[Literal(Path::new(~[~"core", ~"cmp", ~"Eq"]))],
generics: LifetimeBounds::empty(),
methods: ~[
md!(~"lt", true, false),
md!(~"le", true, true),
Expand Down Expand Up @@ -97,19 +101,19 @@ fn cs_ord(less: bool, equal: bool,
}

let cmp = build::mk_method_call(cx, span,
self_f, cx.ident_of(~"eq"), other_fs);
self_f, cx.ident_of(~"eq"), other_fs.to_owned());
let subexpr = build::mk_simple_block(cx, span, subexpr);
let elseif = expr_if(cmp, subexpr, Some(false_blk_expr));
let elseif = build::mk_expr(cx, span, elseif);

let cmp = build::mk_method_call(cx, span,
self_f, binop, other_fs);
self_f, binop, other_fs.to_owned());
let if_ = expr_if(cmp, true_blk, Some(elseif));

build::mk_expr(cx, span, if_)
},
base,
|cx, span, args| {
|cx, span, args, _| {
// nonmatching enums, order by the order the variants are
// written
match args {
Expand Down
13 changes: 7 additions & 6 deletions src/libsyntax/ext/deriving/cmp/totaleq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,27 @@ use ext::base::ext_ctxt;
use ext::build;
use ext::deriving::generic::*;

use core::option::Some;

pub fn expand_deriving_totaleq(cx: @ext_ctxt,
span: span,
mitem: @meta_item,
in_items: ~[@item]) -> ~[@item] {

fn cs_equals(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
cs_and(|cx, span, _| build::mk_bool(cx, span, false),
cs_and(|cx, span, _, _| build::mk_bool(cx, span, false),
cx, span, substr)
}

let trait_def = TraitDef {
path: ~[~"core", ~"cmp", ~"TotalEq"],
path: Path::new(~[~"core", ~"cmp", ~"TotalEq"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),
methods: ~[
MethodDef {
name: ~"equals",
output_type: Some(~[~"bool"]),
nargs: 1,
generics: LifetimeBounds::empty(),
self_ty: borrowed_explicit_self(),
args: ~[borrowed_self()],
ret_ty: Literal(Path::new(~[~"bool"])),
const_nonmatching: true,
combine_substructure: cs_equals
}
Expand Down
12 changes: 7 additions & 5 deletions src/libsyntax/ext/deriving/cmp/totalord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,22 @@ use ext::base::ext_ctxt;
use ext::build;
use ext::deriving::generic::*;
use core::cmp::{Ordering, Equal, Less, Greater};
use core::option::Some;

pub fn expand_deriving_totalord(cx: @ext_ctxt,
span: span,
mitem: @meta_item,
in_items: ~[@item]) -> ~[@item] {
let trait_def = TraitDef {
path: ~[~"core", ~"cmp", ~"TotalOrd"],
path: Path::new(~[~"core", ~"cmp", ~"TotalOrd"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),
methods: ~[
MethodDef {
name: ~"cmp",
output_type: Some(~[~"core", ~"cmp", ~"Ordering"]),
nargs: 1,
generics: LifetimeBounds::empty(),
self_ty: borrowed_explicit_self(),
args: ~[borrowed_self()],
ret_ty: Literal(Path::new(~[~"core", ~"cmp", ~"Ordering"])),
const_nonmatching: false,
combine_substructure: cs_cmp
}
Expand Down Expand Up @@ -64,7 +66,7 @@ pub fn cs_cmp(cx: @ext_ctxt, span: span,
build::mk_call_global(cx, span, lexical_ord, ~[old, new])
},
ordering_const(cx, span, Equal),
|cx, span, list| {
|cx, span, list, _| {
match list {
// an earlier nonmatching variant is Less than a
// later one
Expand Down
Loading