auto merge of #6267 : huonw/rust/syntax-deriving-generaliseder, r=nikomatsakis

This "finishes" the generic deriving code (which I started in #5640), in the sense it supports everything that I can think of being useful. (Including lifetimes and type parameters on methods and traits, arguments and return values of (almost) any type, static methods.)

It closes #6149, but met with #6257, so the following doesn't work:
```rust
#[deriving(TotalEq)]
struct Foo<'self>(&'self int);
```
(It only fails for `TotalOrd`, `TotalEq` and `Clone`, since they are the only ones that call a method directly on sub-elements of the type, which means that the auto-deref interferes with the pointer.)

It also makes `Rand` (chooses a random variant, fills the fields with random values, including recursively for recursive types) and `ToStr` (`x.to_str()` is the same as `fmt!("%?", x)`) derivable, as well as converting IterBytes to the generic code (which made the code 2.5x shorter, more robust and added support for tuple structs).

({En,De}codable are trickier, so I'll convert them over later.)
This commit is contained in:
bors 2013-05-08 07:24:39 -07:00
commit 8f94ac6118
18 changed files with 1354 additions and 789 deletions

View File

@ -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 {
@ -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,

View File

@ -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,
@ -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
}
@ -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 {

View File

@ -8,15 +8,12 @@
// 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,
@ -24,28 +21,32 @@ pub fn expand_deriving_eq(cx: @ext_ctxt,
// 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)

View File

@ -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),
@ -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 {

View File

@ -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
}

View File

@ -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
}
@ -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

View File

@ -66,6 +66,7 @@ fn create_derived_decodable_impl(
cx.ident_of(~"serialize"),
cx.ident_of(~"Decodable")
],
None,
~[
build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D"))
]
@ -77,7 +78,7 @@ fn create_derived_decodable_impl(
generics,
methods,
trait_path,
generic_ty_params,
Generics { ty_params: generic_ty_params, lifetimes: opt_vec::Empty },
opt_vec::Empty
)
}
@ -96,6 +97,7 @@ fn create_decode_method(
cx,
span,
build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")),
None,
ast::m_mutbl
);
let d_ident = cx.ident_of(~"__d");

View File

@ -66,6 +66,7 @@ fn create_derived_encodable_impl(
cx.ident_of(~"serialize"),
cx.ident_of(~"Encodable")
],
None,
~[
build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E"))
]
@ -77,7 +78,7 @@ fn create_derived_encodable_impl(
generics,
methods,
trait_path,
generic_ty_params,
Generics { ty_params: generic_ty_params, lifetimes: opt_vec::Empty },
opt_vec::Empty
)
}
@ -94,6 +95,7 @@ fn create_encode_method(
cx,
span,
build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")),
None,
ast::m_mutbl
);
let e_arg = build::mk_arg(cx, span, cx.ident_of(~"__e"), e_arg_type);
@ -303,7 +305,7 @@ fn expand_deriving_encodable_enum_method(
// Create the arms of the match in the method body.
let arms = do enum_definition.variants.mapi |i, variant| {
// Create the matching pattern.
let pat = create_enum_variant_pattern(cx, span, variant, ~"__self");
let (pat, fields) = create_enum_variant_pattern(cx, span, variant, ~"__self", ast::m_imm);
// Feed the discriminant to the encode function.
let mut stmts = ~[];
@ -311,11 +313,7 @@ fn expand_deriving_encodable_enum_method(
// Feed each argument in this variant to the encode function
// as well.
let variant_arg_len = variant_arg_count(cx, span, variant);
for uint::range(0, variant_arg_len) |j| {
// Create the expression for this field.
let field_ident = cx.ident_of(~"__self_" + j.to_str());
let field = build::mk_path(cx, span, ~[ field_ident ]);
for fields.eachi |j, &(_, field)| {
// Call the substructure method.
let expr = call_substructure_encode_method(cx, span, field);

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// 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.
//
@ -8,25 +8,37 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast;
use ast::*;
use ast::{meta_item, item, expr};
use codemap::span;
use ext::base::ext_ctxt;
use ext::build;
use ext::deriving::*;
use codemap::{span, spanned};
use ast_util;
use opt_vec;
use ext::deriving::generic::*;
pub fn expand_deriving_iter_bytes(cx: @ext_ctxt,
span: span,
_mitem: @meta_item,
in_items: ~[@item])
-> ~[@item] {
expand_deriving(cx,
span,
in_items,
expand_deriving_iter_bytes_struct_def,
expand_deriving_iter_bytes_enum_def)
mitem: @meta_item,
in_items: ~[@item]) -> ~[@item] {
let trait_def = TraitDef {
path: Path::new(~[~"core", ~"to_bytes", ~"IterBytes"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),
methods: ~[
MethodDef {
name: ~"iter_bytes",
generics: LifetimeBounds::empty(),
self_ty: borrowed_explicit_self(),
args: ~[
Literal(Path::new(~[~"bool"])),
Literal(Path::new(~[~"core", ~"to_bytes", ~"Cb"]))
],
ret_ty: nil_ty(),
const_nonmatching: false,
combine_substructure: iter_bytes_substructure
}
]
};
expand_deriving_generic(cx, span, mitem, in_items, &trait_def)
}
pub fn expand_deriving_obsolete(cx: @ext_ctxt,
@ -39,217 +51,43 @@ pub fn expand_deriving_obsolete(cx: @ext_ctxt,
in_items
}
fn create_derived_iter_bytes_impl(cx: @ext_ctxt,
span: span,
type_ident: ident,
generics: &Generics,
method: @method)
-> @item {
let methods = [ method ];
let trait_path = ~[
cx.ident_of(~"core"),
cx.ident_of(~"to_bytes"),
cx.ident_of(~"IterBytes")
];
let trait_path = build::mk_raw_path_global(span, trait_path);
create_derived_impl(cx, span, type_ident, generics, methods, trait_path,
opt_vec::Empty, opt_vec::Empty)
}
// Creates a method from the given set of statements conforming to the
// signature of the `iter_bytes` method.
fn create_iter_bytes_method(cx: @ext_ctxt,
span: span,
statements: ~[@stmt])
-> @method {
// Create the `lsb0` parameter.
let bool_ident = cx.ident_of(~"bool");
let lsb0_arg_type = build::mk_simple_ty_path(cx, span, bool_ident);
let lsb0_ident = cx.ident_of(~"__lsb0");
let lsb0_arg = build::mk_arg(cx, span, lsb0_ident, lsb0_arg_type);
// Create the `f` parameter.
let core_ident = cx.ident_of(~"core");
let to_bytes_ident = cx.ident_of(~"to_bytes");
let cb_ident = cx.ident_of(~"Cb");
let core_to_bytes_cb_ident = ~[ core_ident, to_bytes_ident, cb_ident ];
let f_arg_type = build::mk_ty_path(cx, span, core_to_bytes_cb_ident);
let f_ident = cx.ident_of(~"__f");
let f_arg = build::mk_arg(cx, span, f_ident, f_arg_type);
// Create the type of the return value.
let output_type = @ast::Ty { id: cx.next_id(), node: ty_nil, span: span };
// Create the function declaration.
let inputs = ~[ lsb0_arg, f_arg ];
let fn_decl = build::mk_fn_decl(inputs, output_type);
// Create the body block.
let body_block = build::mk_block_(cx, span, statements);
// Create the method.
let self_ty = spanned { node: sty_region(None, m_imm), span: span };
let method_ident = cx.ident_of(~"iter_bytes");
@ast::method {
ident: method_ident,
attrs: ~[],
generics: ast_util::empty_generics(),
self_ty: self_ty,
purity: impure_fn,
decl: fn_decl,
body: body_block,
id: cx.next_id(),
span: span,
self_id: cx.next_id(),
vis: public
}
}
fn call_substructure_iter_bytes_method(cx: @ext_ctxt,
span: span,
self_field: @expr)
-> @stmt {
// Gather up the parameters we want to chain along.
let lsb0_ident = cx.ident_of(~"__lsb0");
let f_ident = cx.ident_of(~"__f");
let lsb0_expr = build::mk_path(cx, span, ~[ lsb0_ident ]);
let f_expr = build::mk_path(cx, span, ~[ f_ident ]);
// Call the substructure method.
let iter_bytes_ident = cx.ident_of(~"iter_bytes");
let self_call = build::mk_method_call(cx,
span,
self_field,
iter_bytes_ident,
~[ lsb0_expr, f_expr ]);
// Create a statement out of this expression.
build::mk_stmt(cx, span, self_call)
}
fn expand_deriving_iter_bytes_struct_def(cx: @ext_ctxt,
span: span,
struct_def: &struct_def,
type_ident: ident,
generics: &Generics)
-> @item {
// Create the method.
let method = expand_deriving_iter_bytes_struct_method(cx,
span,
struct_def);
// Create the implementation.
return create_derived_iter_bytes_impl(cx,
span,
type_ident,
generics,
method);
}
fn expand_deriving_iter_bytes_enum_def(cx: @ext_ctxt,
span: span,
enum_definition: &enum_def,
type_ident: ident,
generics: &Generics)
-> @item {
// Create the method.
let method = expand_deriving_iter_bytes_enum_method(cx,
span,
enum_definition);
// Create the implementation.
return create_derived_iter_bytes_impl(cx,
span,
type_ident,
generics,
method);
}
fn expand_deriving_iter_bytes_struct_method(cx: @ext_ctxt,
span: span,
struct_def: &struct_def)
-> @method {
let self_ident = cx.ident_of(~"self");
// Create the body of the method.
let mut statements = ~[];
for struct_def.fields.each |struct_field| {
match struct_field.node.kind {
named_field(ident, _, _) => {
// Create the accessor for this field.
let self_field = build::mk_access(cx,
span,
~[ self_ident ],
ident);
// Call the substructure method.
let stmt = call_substructure_iter_bytes_method(cx,
span,
self_field);
statements.push(stmt);
}
unnamed_field => {
cx.span_unimpl(span,
~"unnamed fields with `deriving(IterBytes)`");
}
}
}
// Create the method itself.
return create_iter_bytes_method(cx, span, statements);
}
fn expand_deriving_iter_bytes_enum_method(cx: @ext_ctxt,
span: span,
enum_definition: &enum_def)
-> @method {
// Create the arms of the match in the method body.
let arms = do enum_definition.variants.mapi |i, variant| {
// Create the matching pattern.
let pat = create_enum_variant_pattern(cx, span, variant, ~"__self");
// Determine the discriminant. We will feed this value to the byte
// iteration function.
let discriminant;
match variant.node.disr_expr {
Some(copy disr_expr) => discriminant = disr_expr,
None => discriminant = build::mk_uint(cx, span, i),
}
// Feed the discriminant to the byte iteration function.
let mut stmts = ~[];
let discrim_stmt = call_substructure_iter_bytes_method(cx,
span,
discriminant);
stmts.push(discrim_stmt);
// Feed each argument in this variant to the byte iteration function
// as well.
for uint::range(0, variant_arg_count(cx, span, variant)) |j| {
// Create the expression for this field.
let field_ident = cx.ident_of(~"__self_" + j.to_str());
let field = build::mk_path(cx, span, ~[ field_ident ]);
// Call the substructure method.
let stmt = call_substructure_iter_bytes_method(cx, span, field);
stmts.push(stmt);
}
// Create the pattern body.
let match_body_block = build::mk_block_(cx, span, stmts);
// Create the arm.
ast::arm {
pats: ~[ pat ],
guard: None,
body: match_body_block,
}
fn iter_bytes_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
let lsb0_f = match substr.nonself_args {
[l, f] => ~[l, f],
_ => cx.span_bug(span, "Incorrect number of arguments in `deriving(IterBytes)`")
};
let iter_bytes_ident = substr.method_ident;
let call_iterbytes = |thing_expr| {
build::mk_stmt(
cx, span,
build::mk_method_call(cx, span,
thing_expr, iter_bytes_ident,
copy lsb0_f))
};
let mut stmts = ~[];
let fields;
match *substr.fields {
Struct(ref fs) => {
fields = fs
}
EnumMatching(copy index, ref variant, ref fs) => {
// Determine the discriminant. We will feed this value to the byte
// iteration function.
let discriminant = match variant.node.disr_expr {
Some(copy d)=> d,
None => build::mk_uint(cx, span, index)
};
// Create the method body.
let self_match_expr = expand_enum_or_struct_match(cx, span, arms);
let self_match_stmt = build::mk_stmt(cx, span, self_match_expr);
stmts.push(call_iterbytes(discriminant));
// Create the method.
create_iter_bytes_method(cx, span, ~[ self_match_stmt ])
}
fields = fs;
}
_ => cx.span_bug(span, "Impossible substructure in `deriving(IterBytes)`")
}
for fields.each |&(_, field, _)| {
stmts.push(call_iterbytes(field));
}
build::mk_block(cx, span, ~[], stmts, None)
}

View File

@ -12,14 +12,7 @@
/// #[deriving(IterBytes)] extensions.
use ast;
use ast::{Ty, bind_by_ref, deref, enum_def};
use ast::{expr, expr_match, ident, item, item_};
use ast::{item_enum, item_impl, item_struct, Generics};
use ast::{m_imm, meta_item, method};
use ast::{named_field, pat, pat_ident, public};
use ast::{struct_def, struct_variant_kind};
use ast::{tuple_variant_kind};
use ast::{ty_path, unnamed_field, variant};
use ast::{Ty, enum_def, expr, ident, item, Generics, meta_item, struct_def};
use ext::base::ext_ctxt;
use ext::build;
use codemap::{span, respan};
@ -30,6 +23,8 @@ pub mod clone;
pub mod iter_bytes;
pub mod encodable;
pub mod decodable;
pub mod rand;
pub mod to_str;
#[path="cmp/eq.rs"]
pub mod eq;
@ -78,23 +73,25 @@ pub fn expand_meta_deriving(cx: @ext_ctxt,
meta_name_value(tname, _) |
meta_list(tname, _) |
meta_word(tname) => {
macro_rules! expand(($func:path) => ($func(cx, titem.span,
titem, in_items)));
match *tname {
~"Clone" => clone::expand_deriving_clone(cx,
titem.span, titem, in_items),
~"IterBytes" => iter_bytes::expand_deriving_iter_bytes(cx,
titem.span, titem, in_items),
~"Encodable" => encodable::expand_deriving_encodable(cx,
titem.span, titem, in_items),
~"Decodable" => decodable::expand_deriving_decodable(cx,
titem.span, titem, in_items),
~"Eq" => eq::expand_deriving_eq(cx, titem.span,
titem, in_items),
~"TotalEq" => totaleq::expand_deriving_totaleq(cx, titem.span,
titem, in_items),
~"Ord" => ord::expand_deriving_ord(cx, titem.span,
titem, in_items),
~"TotalOrd" => totalord::expand_deriving_totalord(cx, titem.span,
titem, in_items),
~"Clone" => expand!(clone::expand_deriving_clone),
~"IterBytes" => expand!(iter_bytes::expand_deriving_iter_bytes),
~"Encodable" => expand!(encodable::expand_deriving_encodable),
~"Decodable" => expand!(decodable::expand_deriving_decodable),
~"Eq" => expand!(eq::expand_deriving_eq),
~"TotalEq" => expand!(totaleq::expand_deriving_totaleq),
~"Ord" => expand!(ord::expand_deriving_ord),
~"TotalOrd" => expand!(totalord::expand_deriving_totalord),
~"Rand" => expand!(rand::expand_deriving_rand),
~"ToStr" => expand!(to_str::expand_deriving_to_str),
tname => {
cx.span_err(titem.span, fmt!("unknown \
`deriving` trait: `%s`", tname));
@ -118,14 +115,14 @@ pub fn expand_deriving(cx: @ext_ctxt,
for in_items.each |item| {
result.push(copy *item);
match item.node {
item_struct(struct_def, ref generics) => {
ast::item_struct(struct_def, ref generics) => {
result.push(expand_deriving_struct_def(cx,
span,
struct_def,
item.ident,
generics));
}
item_enum(ref enum_definition, ref generics) => {
ast::item_enum(ref enum_definition, ref generics) => {
result.push(expand_deriving_enum_def(cx,
span,
enum_definition,
@ -138,7 +135,7 @@ pub fn expand_deriving(cx: @ext_ctxt,
result
}
fn create_impl_item(cx: @ext_ctxt, span: span, item: item_) -> @item {
fn create_impl_item(cx: @ext_ctxt, span: span, item: ast::item_) -> @item {
let doc_attr = respan(span,
ast::lit_str(@~"Automatically derived."));
let doc_attr = respan(span, ast::meta_name_value(@~"doc", doc_attr));
@ -154,7 +151,7 @@ fn create_impl_item(cx: @ext_ctxt, span: span, item: item_) -> @item {
attrs: ~[doc_attr],
id: cx.next_id(),
node: item,
vis: public,
vis: ast::public,
span: span,
}
}
@ -173,22 +170,29 @@ pub fn create_self_type_with_params(cx: @ext_ctxt,
self_ty_params.push(self_ty_param);
}
let lifetime = if generics.lifetimes.is_empty() {
None
} else {
Some(@*generics.lifetimes.get(0))
};
// Create the type of `self`.
let self_type = build::mk_raw_path_(span,
~[ type_ident ],
lifetime,
self_ty_params);
let self_type = ty_path(self_type, cx.next_id());
@ast::Ty { id: cx.next_id(), node: self_type, span: span }
build::mk_ty_path_path(cx, span, self_type)
}
pub fn create_derived_impl(cx: @ext_ctxt,
span: span,
type_ident: ident,
generics: &Generics,
methods: &[@method],
methods: &[@ast::method],
trait_path: @ast::Path,
mut impl_ty_params: opt_vec::OptVec<ast::TyParam>,
bounds_paths: opt_vec::OptVec<~[ident]>)
mut impl_generics: Generics,
bounds_paths: opt_vec::OptVec<@ast::Path>)
-> @item {
/*!
*
@ -204,21 +208,22 @@ pub fn create_derived_impl(cx: @ext_ctxt,
*/
// Copy the lifetimes
let impl_lifetimes = generics.lifetimes.map(|l| {
build::mk_lifetime(cx, l.span, l.ident)
});
for generics.lifetimes.each |l| {
impl_generics.lifetimes.push(copy *l)
};
// Create the type parameters.
for generics.ty_params.each |ty_param| {
// extra restrictions on the generics parameters to the type being derived upon
let mut bounds = do bounds_paths.map |&bound_path| {
build::mk_trait_ty_param_bound_global(cx, span, bound_path)
build::mk_trait_ty_param_bound_(cx, bound_path)
};
let this_trait_bound =
build::mk_trait_ty_param_bound_(cx, trait_path);
bounds.push(this_trait_bound);
impl_ty_params.push(build::mk_ty_param(cx, ty_param.ident, @bounds));
impl_generics.ty_params.push(build::mk_ty_param(cx, ty_param.ident, @bounds));
}
// Create the reference to the trait.
@ -231,8 +236,7 @@ pub fn create_derived_impl(cx: @ext_ctxt,
generics);
// Create the impl item.
let impl_item = item_impl(Generics {lifetimes: impl_lifetimes,
ty_params: impl_ty_params},
let impl_item = ast::item_impl(impl_generics,
Some(trait_ref),
self_type,
methods.map(|x| *x));
@ -240,106 +244,128 @@ pub fn create_derived_impl(cx: @ext_ctxt,
}
pub fn create_subpatterns(cx: @ext_ctxt,
span: span,
prefix: ~str,
n: uint)
-> ~[@pat] {
let mut subpats = ~[];
for uint::range(0, n) |_i| {
// Create the subidentifier.
let index = subpats.len();
let ident = cx.ident_of(fmt!("%s_%u", prefix, index));
// Create the subpattern.
let subpath = build::mk_raw_path(span, ~[ ident ]);
let subpat = pat_ident(bind_by_ref(m_imm), subpath, None);
let subpat = build::mk_pat(cx, span, subpat);
subpats.push(subpat);
span: span,
field_paths: ~[@ast::Path],
mutbl: ast::mutability)
-> ~[@ast::pat] {
do field_paths.map |&path| {
build::mk_pat(cx, span,
ast::pat_ident(ast::bind_by_ref(mutbl), path, None))
}
return subpats;
}
pub fn is_struct_tuple(struct_def: &struct_def) -> bool {
struct_def.fields.len() > 0 && struct_def.fields.all(|f| {
match f.node.kind {
named_field(*) => false,
unnamed_field => true
}
})
#[deriving(Eq)] // dogfooding!
enum StructType {
Unknown, Record, Tuple
}
pub fn create_struct_pattern(cx: @ext_ctxt,
span: span,
struct_ident: ident,
struct_def: &struct_def,
prefix: ~str,
mutbl: ast::mutability)
-> (@ast::pat, ~[(Option<ident>, @expr)]) {
if struct_def.fields.is_empty() {
return (
build::mk_pat_ident_with_binding_mode(
cx, span, struct_ident, ast::bind_infer),
~[]);
}
let matching_path = build::mk_raw_path(span, ~[ struct_ident ]);
let mut paths = ~[], ident_expr = ~[];
let mut struct_type = Unknown;
for struct_def.fields.eachi |i, struct_field| {
let opt_id = match struct_field.node.kind {
ast::named_field(ident, _, _) if (struct_type == Unknown ||
struct_type == Record) => {
struct_type = Record;
Some(ident)
}
ast::unnamed_field if (struct_type == Unknown ||
struct_type == Tuple) => {
struct_type = Tuple;
None
}
_ => {
cx.span_bug(span, "A struct with named and unnamed fields in `deriving`");
}
};
let path = build::mk_raw_path(span,
~[ cx.ident_of(fmt!("%s_%u", prefix, i)) ]);
paths.push(path);
ident_expr.push((opt_id, build::mk_path_raw(cx, span, path)));
}
let subpats = create_subpatterns(cx, span, paths, mutbl);
// struct_type is definitely not Unknown, since struct_def.fields
// must be nonempty to reach here
let pattern = if struct_type == Record {
let field_pats = do vec::build |push| {
for vec::each2(subpats, ident_expr) |&pat, &(id, _)| {
// id is guaranteed to be Some
push(ast::field_pat { ident: id.get(), pat: pat })
}
};
build::mk_pat_struct(cx, span, matching_path, field_pats)
} else {
build::mk_pat_enum(cx, span, matching_path, subpats)
};
(pattern, ident_expr)
}
pub fn create_enum_variant_pattern(cx: @ext_ctxt,
span: span,
variant: &variant,
prefix: ~str)
-> @pat {
span: span,
variant: &ast::variant,
prefix: ~str,
mutbl: ast::mutability)
-> (@ast::pat, ~[(Option<ident>, @expr)]) {
let variant_ident = variant.node.name;
match variant.node.kind {
tuple_variant_kind(ref variant_args) => {
if variant_args.len() == 0 {
return build::mk_pat_ident_with_binding_mode(
cx, span, variant_ident, ast::bind_infer);
ast::tuple_variant_kind(ref variant_args) => {
if variant_args.is_empty() {
return (build::mk_pat_ident_with_binding_mode(
cx, span, variant_ident, ast::bind_infer), ~[]);
}
let matching_path = build::mk_raw_path(span, ~[ variant_ident ]);
let subpats = create_subpatterns(cx,
span,
prefix,
variant_args.len());
return build::mk_pat_enum(cx, span, matching_path, subpats);
}
struct_variant_kind(struct_def) => {
let matching_path = build::mk_raw_path(span, ~[ variant_ident ]);
let subpats = create_subpatterns(cx,
span,
prefix,
struct_def.fields.len());
let mut paths = ~[], ident_expr = ~[];
for uint::range(0, variant_args.len()) |i| {
let path = build::mk_raw_path(span,
~[ cx.ident_of(fmt!("%s_%u", prefix, i)) ]);
let field_pats = do struct_def.fields.mapi |i, struct_field| {
let ident = match struct_field.node.kind {
named_field(ident, _, _) => ident,
unnamed_field => {
cx.span_bug(span, ~"unexpected unnamed field");
}
};
ast::field_pat { ident: ident, pat: subpats[i] }
};
build::mk_pat_struct(cx, span, matching_path, field_pats)
}
}
}
pub fn variant_arg_count(_cx: @ext_ctxt, _span: span, variant: &variant) -> uint {
match variant.node.kind {
tuple_variant_kind(ref args) => args.len(),
struct_variant_kind(ref struct_def) => struct_def.fields.len(),
}
}
/// Iterate through the idents of the variant arguments. The field is
/// unnamed (i.e. it's not a struct-like enum), then `None`.
pub fn each_variant_arg_ident(_cx: @ext_ctxt, _span: span,
variant: &variant, it: &fn(uint, Option<ident>) -> bool) {
match variant.node.kind {
tuple_variant_kind(ref args) => {
for uint::range(0, args.len()) |i| {
if !it(i, None) { break }
paths.push(path);
ident_expr.push((None, build::mk_path_raw(cx, span, path)));
}
let subpats = create_subpatterns(cx, span, paths, mutbl);
(build::mk_pat_enum(cx, span, matching_path, subpats),
ident_expr)
}
struct_variant_kind(ref struct_def) => {
for struct_def.fields.eachi |i, f| {
let id = match f.node.kind {
named_field(ident, _, _) => Some(ident),
unnamed_field => None
};
if !it(i, id) { break }
}
ast::struct_variant_kind(struct_def) => {
create_struct_pattern(cx, span,
variant_ident, struct_def,
prefix,
mutbl)
}
}
}
pub fn variant_arg_count(_cx: @ext_ctxt, _span: span, variant: &ast::variant) -> uint {
match variant.node.kind {
ast::tuple_variant_kind(ref args) => args.len(),
ast::struct_variant_kind(ref struct_def) => struct_def.fields.len(),
}
}
pub fn expand_enum_or_struct_match(cx: @ext_ctxt,
span: span,
@ -347,7 +373,7 @@ pub fn expand_enum_or_struct_match(cx: @ext_ctxt,
-> @expr {
let self_ident = cx.ident_of(~"self");
let self_expr = build::mk_path(cx, span, ~[ self_ident ]);
let self_expr = build::mk_unary(cx, span, deref, self_expr);
let self_match_expr = expr_match(self_expr, arms);
let self_expr = build::mk_unary(cx, span, ast::deref, self_expr);
let self_match_expr = ast::expr_match(self_expr, arms);
build::mk_expr(cx, span, self_match_expr)
}

View File

@ -0,0 +1,136 @@
// Copyright 2012-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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast;
use ast::{meta_item, item, expr, ident};
use codemap::span;
use ext::base::ext_ctxt;
use ext::build;
use ext::deriving::generic::*;
pub fn expand_deriving_rand(cx: @ext_ctxt,
span: span,
mitem: @meta_item,
in_items: ~[@item])
-> ~[@item] {
let trait_def = TraitDef {
path: Path::new(~[~"core", ~"rand", ~"Rand"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),
methods: ~[
MethodDef {
name: ~"rand",
generics: LifetimeBounds {
lifetimes: ~[],
bounds: ~[(~"R",
~[ Path::new(~[~"core", ~"rand", ~"Rng"]) ])]
},
self_ty: None,
args: ~[
Ptr(~Literal(Path::new_local(~"R")),
Borrowed(None, ast::m_imm))
],
ret_ty: Self,
const_nonmatching: false,
combine_substructure: rand_substructure
}
]
};
expand_deriving_generic(cx, span, mitem, in_items, &trait_def)
}
fn rand_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
let rng = match substr.nonself_args {
[rng] => ~[ rng ],
_ => cx.bug("Incorrect number of arguments to `rand` in `deriving(Rand)`")
};
let rand_ident = ~[
cx.ident_of(~"core"),
cx.ident_of(~"rand"),
cx.ident_of(~"Rand"),
cx.ident_of(~"rand")
];
let rand_call = || {
build::mk_call_global(cx, span,
copy rand_ident, copy rng)
};
return match *substr.fields {
StaticStruct(_, ref summary) => {
rand_thing(cx, span, substr.type_ident, summary, rand_call)
}
StaticEnum(_, ref variants) => {
if variants.is_empty() {
cx.span_fatal(span, "`Rand` cannot be derived for enums with no variants");
}
let variant_count = build::mk_uint(cx, span, variants.len());
// need to specify the uint-ness of the random number
let u32_ty = build::mk_ty_path(cx, span, ~[cx.ident_of(~"uint")]);
let r_ty = build::mk_ty_path(cx, span, ~[cx.ident_of(~"R")]);
let rand_name = build::mk_raw_path_(span, copy rand_ident, None, ~[ u32_ty, r_ty ]);
let rand_name = build::mk_path_raw(cx, span, rand_name);
let rv_call = build::mk_call_(cx, span, rand_name, copy rng);
// rand() % variants.len()
let rand_variant = build::mk_binary(cx, span, ast::rem,
rv_call, variant_count);
let mut arms = do variants.mapi |i, id_sum| {
let i_expr = build::mk_uint(cx, span, i);
let pat = build::mk_pat_lit(cx, span, i_expr);
match *id_sum {
(ident, ref summary) => {
build::mk_arm(cx, span,
~[ pat ],
rand_thing(cx, span, ident, summary, rand_call))
}
}
};
// _ => {} at the end. Should never occur
arms.push(build::mk_unreachable_arm(cx, span));
build::mk_expr(cx, span,
ast::expr_match(rand_variant, arms))
}
_ => cx.bug("Non-static method in `deriving(Rand)`")
};
fn rand_thing(cx: @ext_ctxt, span: span,
ctor_ident: ident,
summary: &Either<uint, ~[ident]>,
rand_call: &fn() -> @expr) -> @expr {
let ctor_ident = ~[ ctor_ident ];
match *summary {
Left(copy count) => {
if count == 0 {
build::mk_path(cx, span, ctor_ident)
} else {
let exprs = vec::from_fn(count, |_| rand_call());
build::mk_call(cx, span, ctor_ident, exprs)
}
}
Right(ref fields) => {
let rand_fields = do fields.map |ident| {
build::Field {
ident: *ident,
ex: rand_call()
}
};
build::mk_struct_e(cx, span, ctor_ident, rand_fields)
}
}
}
}

View File

@ -0,0 +1,54 @@
// Copyright 2012-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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// 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::*;
pub fn expand_deriving_to_str(cx: @ext_ctxt,
span: span,
mitem: @meta_item,
in_items: ~[@item])
-> ~[@item] {
let trait_def = TraitDef {
path: Path::new(~[~"core", ~"to_str", ~"ToStr"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),
methods: ~[
MethodDef {
name: ~"to_str",
generics: LifetimeBounds::empty(),
self_ty: borrowed_explicit_self(),
args: ~[],
ret_ty: Ptr(~Literal(Path::new_local(~"str")), Owned),
const_nonmatching: false,
combine_substructure: to_str_substructure
}
]
};
expand_deriving_generic(cx, span, mitem, in_items, &trait_def)
}
fn to_str_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
match substr.self_args {
[self_obj] => {
let self_addr = build::mk_addr_of(cx, span, self_obj);
build::mk_call_global(cx, span,
~[cx.ident_of(~"core"),
cx.ident_of(~"sys"),
cx.ident_of(~"log_str")],
~[self_addr])
}
_ => cx.span_bug(span, ~"Invalid number of arguments in `deriving(ToStr)`")
}
}

View File

@ -0,0 +1,242 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
A mini version of ast::Ty, which is easier to use, and features an
explicit `Self` type to use when specifying impls to be derived.
*/
use ast;
use ast::{expr,Generics,ident};
use ext::base::ext_ctxt;
use ext::build;
use codemap::{span,respan};
use opt_vec;
/// The types of pointers
#[deriving(Eq)]
pub enum PtrTy {
Owned, // ~
Managed(ast::mutability), // @[mut]
Borrowed(Option<~str>, ast::mutability), // &['lifetime] [mut]
}
/// A path, e.g. `::core::option::Option::<int>` (global). Has support
/// for type parameters and a lifetime.
#[deriving(Eq)]
pub struct Path {
path: ~[~str],
lifetime: Option<~str>,
params: ~[~Ty],
global: bool
}
pub impl Path {
fn new(path: ~[~str]) -> Path {
Path::new_(path, None, ~[], true)
}
fn new_local(path: ~str) -> Path {
Path::new_(~[ path ], None, ~[], false)
}
fn new_(path: ~[~str], lifetime: Option<~str>, params: ~[~Ty], global: bool) -> Path {
Path {
path: path,
lifetime: lifetime,
params: params,
global: global
}
}
fn to_ty(&self, cx: @ext_ctxt, span: span,
self_ty: ident, self_generics: &Generics) -> @ast::Ty {
build::mk_ty_path_path(cx, span,
self.to_path(cx, span,
self_ty, self_generics))
}
fn to_path(&self, cx: @ext_ctxt, span: span,
self_ty: ident, self_generics: &Generics) -> @ast::Path {
let idents = self.path.map(|s| cx.ident_of(*s) );
let lt = mk_lifetime(cx, span, self.lifetime);
let tys = self.params.map(|t| t.to_ty(cx, span, self_ty, self_generics));
if self.global {
build::mk_raw_path_global_(span, idents, lt, tys)
} else {
build::mk_raw_path_(span, idents, lt, tys)
}
}
}
/// A type. Supports pointers (except for *), Self, and literals
#[deriving(Eq)]
pub enum Ty {
Self,
// &/~/@ Ty
Ptr(~Ty, PtrTy),
// mod::mod::Type<[lifetime], [Params...]>, including a plain type
// parameter, and things like `int`
Literal(Path),
// includes nil
Tuple(~[Ty])
}
pub fn borrowed_ptrty() -> PtrTy {
Borrowed(None, ast::m_imm)
}
pub fn borrowed(ty: ~Ty) -> Ty {
Ptr(ty, borrowed_ptrty())
}
pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> {
Some(Some(borrowed_ptrty()))
}
pub fn borrowed_self() -> Ty {
borrowed(~Self)
}
pub fn nil_ty() -> Ty {
Tuple(~[])
}
fn mk_lifetime(cx: @ext_ctxt, span: span, lt: Option<~str>) -> Option<@ast::Lifetime> {
match lt {
Some(s) => Some(@build::mk_lifetime(cx, span, cx.ident_of(s))),
None => None
}
}
pub impl Ty {
fn to_ty(&self, cx: @ext_ctxt, span: span,
self_ty: ident, self_generics: &Generics) -> @ast::Ty {
match *self {
Ptr(ref ty, ref ptr) => {
let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
match *ptr {
Owned => {
build::mk_ty_uniq(cx, span, raw_ty)
}
Managed(copy mutbl) => {
build::mk_ty_box(cx, span, raw_ty, mutbl)
}
Borrowed(copy lt, copy mutbl) => {
let lt = mk_lifetime(cx, span, lt);
build::mk_ty_rptr(cx, span, raw_ty, lt, mutbl)
}
}
}
Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) }
Self => {
build::mk_ty_path_path(cx, span, self.to_path(cx, span, self_ty, self_generics))
}
Tuple(ref fields) => {
let ty = if fields.is_empty() {
ast::ty_nil
} else {
ast::ty_tup(fields.map(|f| f.to_ty(cx, span, self_ty, self_generics)))
};
build::mk_ty(cx, span, ty)
}
}
}
fn to_path(&self, cx: @ext_ctxt, span: span,
self_ty: ident, self_generics: &Generics) -> @ast::Path {
match *self {
Self => {
let self_params = do self_generics.ty_params.map |ty_param| {
build::mk_ty_path(cx, span, ~[ ty_param.ident ])
};
let lifetime = if self_generics.lifetimes.is_empty() {
None
} else {
Some(@*self_generics.lifetimes.get(0))
};
build::mk_raw_path_(span, ~[self_ty], lifetime,
opt_vec::take_vec(self_params))
}
Literal(ref p) => {
p.to_path(cx, span, self_ty, self_generics)
}
Ptr(*) => { cx.span_bug(span, ~"Pointer in a path in generic `deriving`") }
Tuple(*) => { cx.span_bug(span, ~"Tuple in a path in generic `deriving`") }
}
}
}
fn mk_ty_param(cx: @ext_ctxt, span: span, name: ~str, bounds: ~[Path],
self_ident: ident, self_generics: &Generics) -> ast::TyParam {
let bounds = opt_vec::from(
do bounds.map |b| {
let path = b.to_path(cx, span, self_ident, self_generics);
build::mk_trait_ty_param_bound_(cx, path)
});
build::mk_ty_param(cx, cx.ident_of(name), @bounds)
}
fn mk_generics(lifetimes: ~[ast::Lifetime], ty_params: ~[ast::TyParam]) -> Generics {
Generics {
lifetimes: opt_vec::from(lifetimes),
ty_params: opt_vec::from(ty_params)
}
}
/// Lifetimes and bounds on type paramers
pub struct LifetimeBounds {
lifetimes: ~[~str],
bounds: ~[(~str, ~[Path])]
}
pub impl LifetimeBounds {
fn empty() -> LifetimeBounds {
LifetimeBounds {
lifetimes: ~[], bounds: ~[]
}
}
fn to_generics(&self, cx: @ext_ctxt, span: span,
self_ty: ident, self_generics: &Generics) -> Generics {
let lifetimes = do self.lifetimes.map |&lt| {
build::mk_lifetime(cx, span, cx.ident_of(lt))
};
let ty_params = do self.bounds.map |&(name, bounds)| {
mk_ty_param(cx, span, name, bounds, self_ty, self_generics)
};
mk_generics(lifetimes, ty_params)
}
}
pub fn get_explicit_self(cx: @ext_ctxt, span: span, self_ptr: Option<PtrTy>)
-> (@expr, ast::self_ty) {
let self_path = build::mk_path(cx, span, ~[cx.ident_of(~"self")]);
match self_ptr {
None => {
(self_path, respan(span, ast::sty_value))
}
Some(ptr) => {
let self_ty = respan(
span,
match ptr {
Owned => ast::sty_uniq(ast::m_imm),
Managed(mutbl) => ast::sty_box(mutbl),
Borrowed(lt, mutbl) => {
let lt = lt.map(|s| @build::mk_lifetime(cx, span,
cx.ident_of(*s)));
ast::sty_region(lt, mutbl)
}
});
let self_expr = build::mk_deref(cx, span, self_path);
(self_expr, self_ty)
}
}
}

View File

@ -0,0 +1,39 @@
// xfail-fast #6330
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[deriving(Rand)]
struct A;
#[deriving(Rand)]
struct B(int, int);
#[deriving(Rand)]
struct C {
x: f64,
y: (u8, u8)
}
#[deriving(Rand)]
enum D {
D0,
D1(uint),
D2 { x: (), y: () }
}
fn main() {
// check there's no segfaults
for 20.times {
rand::random::<A>();
rand::random::<B>();
rand::random::<C>();
rand::random::<D>();
}
}

View File

@ -0,0 +1,32 @@
// xfail-test FIXME #6257
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use core::cmp::{Less,Equal,Greater};
#[deriving(TotalEq,TotalOrd)]
struct A<'self> {
x: &'self int
}
fn main() {
let a = A { x: &1 }, b = A { x: &2 };
assert!(a.equals(&a));
assert!(b.equals(&b));
assert_eq!(a.cmp(&a), Equal);
assert_eq!(b.cmp(&b), Equal);
assert_eq!(a.cmp(&b), Less);
assert_eq!(b.cmp(&a), Greater);
}

View File

@ -0,0 +1,33 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[deriving(Eq,Ord)]
struct A<'self> {
x: &'self int
}
fn main() {
let a = A { x: &1 }, b = A { x: &2 };
assert_eq!(a, a);
assert_eq!(b, b);
assert!(a < b);
assert!(b > a);
assert!(a <= b);
assert!(a <= a);
assert!(b <= b);
assert!(b >= a);
assert!(b >= b);
assert!(a >= a);
}

View File

@ -0,0 +1,45 @@
// xfail-fast #6330
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[deriving(Rand,ToStr)]
struct A;
#[deriving(Rand,ToStr)]
struct B(int, int);
#[deriving(Rand,ToStr)]
struct C {
x: f64,
y: (u8, u8)
}
#[deriving(Rand,ToStr)]
enum D {
D0,
D1(uint),
D2 { x: (), y: () }
}
fn main() {
macro_rules! t(
($ty:ty) => {{
let x =rand::random::<$ty>();
assert_eq!(x.to_str(), fmt!("%?", x));
}}
);
for 20.times {
t!(A);
t!(B);
t!(C);
t!(D);
}
}