libsyntax: Implement deriving
correctly for type-parameterized structs and enums. r=brson
This commit is contained in:
parent
57588edf3b
commit
e6d87a3ef4
@ -39,6 +39,12 @@ fn mk_raw_path(sp: span, idents: ~[ast::ident]) -> @ast::path {
|
||||
rp: None, types: ~[]};
|
||||
return p;
|
||||
}
|
||||
fn mk_raw_path_(sp: span,
|
||||
idents: ~[ast::ident],
|
||||
+types: ~[@ast::Ty])
|
||||
-> @ast::path {
|
||||
@{ span: sp, global: false, idents: idents, rp: None, types: move types }
|
||||
}
|
||||
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)))
|
||||
@ -224,4 +230,10 @@ fn mk_arg(cx: ext_ctxt,
|
||||
fn mk_fn_decl(+inputs: ~[ast::arg], output: @ast::Ty) -> ast::fn_decl {
|
||||
{ inputs: move inputs, output: output, cf: ast::return_val }
|
||||
}
|
||||
fn mk_ty_param(cx: ext_ctxt,
|
||||
ident: ast::ident,
|
||||
bounds: @~[ast::ty_param_bound])
|
||||
-> ast::ty_param {
|
||||
{ ident: ident, id: cx.next_id(), bounds: bounds }
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,13 @@
|
||||
/// The compiler code necessary to implement the #[deriving_eq] and
|
||||
/// #[deriving_iter_bytes] extensions.
|
||||
|
||||
use ast::{and, bind_by_ref, binop, blk, default_blk, deref, enum_def};
|
||||
use ast::{enum_variant_kind, expr};
|
||||
use ast::{expr_, expr_addr_of, expr_binary, expr_call, expr_field, expr_lit};
|
||||
use ast::{expr_match, expr_path, expr_unary, ident, infer, item, item_};
|
||||
use ast::{item_class, item_enum, item_impl, lit_bool, m_imm, meta_item};
|
||||
use ast::{method, named_field, or, pat, pat_ident, pat_wild, path, public};
|
||||
use ast::{pure_fn, re_anon, return_val, stmt, struct_def};
|
||||
use ast::{Ty, and, bind_by_ref, binop, deref, enum_def, enum_variant_kind};
|
||||
use ast::{expr, expr_match, ident, item, item_, item_class, item_enum};
|
||||
use ast::{item_impl, m_imm, meta_item, method, named_field, or, pat};
|
||||
use ast::{pat_ident, pat_wild, public, pure_fn, re_anon, stmt, struct_def};
|
||||
use ast::{struct_variant_kind, sty_by_ref, sty_region, tuple_variant_kind};
|
||||
use ast::{ty_nil, ty_path, ty_rptr, unnamed_field, variant};
|
||||
use ast::{ty_nil, ty_param, ty_param_bound, ty_path, ty_rptr, unnamed_field};
|
||||
use ast::{variant};
|
||||
use base::ext_ctxt;
|
||||
use codemap::span;
|
||||
use parse::token::special_idents::clownshoes_extensions;
|
||||
@ -31,13 +29,15 @@ impl Junction {
|
||||
type ExpandDerivingStructDefFn = &fn(ext_ctxt,
|
||||
span,
|
||||
x: &struct_def,
|
||||
ident)
|
||||
-> @item;
|
||||
type ExpandDerivingEnumDefFn = &fn(ext_ctxt,
|
||||
span,
|
||||
x: &enum_def,
|
||||
ident)
|
||||
ident,
|
||||
+y: ~[ty_param])
|
||||
-> @item;
|
||||
type ExpandDerivingEnumDefFn = &fn(ext_ctxt,
|
||||
span,
|
||||
x: &enum_def,
|
||||
ident,
|
||||
+y: ~[ty_param])
|
||||
-> @item;
|
||||
|
||||
pub fn expand_deriving_eq(cx: ext_ctxt,
|
||||
span: span,
|
||||
@ -73,17 +73,19 @@ fn expand_deriving(cx: ext_ctxt,
|
||||
for in_items.each |item| {
|
||||
result.push(copy *item);
|
||||
match item.node {
|
||||
item_class(struct_def, _) => {
|
||||
item_class(struct_def, copy ty_params) => {
|
||||
result.push(expand_deriving_struct_def(cx,
|
||||
span,
|
||||
struct_def,
|
||||
item.ident));
|
||||
item.ident,
|
||||
move ty_params));
|
||||
}
|
||||
item_enum(ref enum_definition, _) => {
|
||||
item_enum(ref enum_definition, copy ty_params) => {
|
||||
result.push(expand_deriving_enum_def(cx,
|
||||
span,
|
||||
enum_definition,
|
||||
item.ident));
|
||||
item.ident,
|
||||
move ty_params));
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
@ -97,7 +99,7 @@ fn create_impl_item(cx: ext_ctxt, span: span, +item: item_) -> @item {
|
||||
attrs: ~[],
|
||||
id: cx.next_id(),
|
||||
node: move item,
|
||||
vis: ast::public,
|
||||
vis: public,
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
@ -108,10 +110,14 @@ fn create_eq_method(cx: ext_ctxt,
|
||||
span: span,
|
||||
method_ident: ident,
|
||||
type_ident: ident,
|
||||
ty_params: &[ty_param],
|
||||
body: @expr)
|
||||
-> @method {
|
||||
// Create the type of the `other` parameter.
|
||||
let arg_path_type = build::mk_simple_ty_path(cx, span, type_ident);
|
||||
let arg_path_type = create_self_type_with_params(cx,
|
||||
span,
|
||||
type_ident,
|
||||
ty_params);
|
||||
let arg_region = @{ id: cx.next_id(), node: re_anon };
|
||||
let arg_type = ty_rptr(arg_region, { ty: arg_path_type, mutbl: m_imm });
|
||||
let arg_type = @{ id: cx.next_id(), node: move arg_type, span: span };
|
||||
@ -153,12 +159,46 @@ fn create_eq_method(cx: ext_ctxt,
|
||||
};
|
||||
}
|
||||
|
||||
fn create_self_type_with_params(cx: ext_ctxt,
|
||||
span: span,
|
||||
type_ident: ident,
|
||||
ty_params: &[ty_param])
|
||||
-> @Ty {
|
||||
// Create the type parameters on the `self` path.
|
||||
let self_ty_params = dvec::DVec();
|
||||
for ty_params.each |ty_param| {
|
||||
let self_ty_param = build::mk_simple_ty_path(cx,
|
||||
span,
|
||||
ty_param.ident);
|
||||
self_ty_params.push(move self_ty_param);
|
||||
}
|
||||
let self_ty_params = dvec::unwrap(move self_ty_params);
|
||||
|
||||
// Create the type of `self`.
|
||||
let self_type = build::mk_raw_path_(span,
|
||||
~[ type_ident ],
|
||||
move self_ty_params);
|
||||
let self_type = ty_path(self_type, cx.next_id());
|
||||
@{ id: cx.next_id(), node: move self_type, span: span }
|
||||
}
|
||||
|
||||
fn create_derived_impl(cx: ext_ctxt,
|
||||
span: span,
|
||||
type_ident: ident,
|
||||
+ty_params: ~[ty_param],
|
||||
methods: &[@method],
|
||||
trait_path: &[ast::ident])
|
||||
trait_path: &[ident])
|
||||
-> @item {
|
||||
// Create the type parameters.
|
||||
let impl_ty_params = dvec::DVec();
|
||||
for ty_params.each |ty_param| {
|
||||
let bound = build::mk_ty_path(cx, span, trait_path.map(|x| *x));
|
||||
let bounds = @~[ ty_param_bound(bound) ];
|
||||
let impl_ty_param = build::mk_ty_param(cx, ty_param.ident, bounds);
|
||||
impl_ty_params.push(move impl_ty_param);
|
||||
}
|
||||
let impl_ty_params = dvec::unwrap(move impl_ty_params);
|
||||
|
||||
// Create the reference to the trait.
|
||||
let trait_path = {
|
||||
span: span,
|
||||
@ -176,12 +216,13 @@ fn create_derived_impl(cx: ext_ctxt,
|
||||
let trait_ref = @move trait_ref;
|
||||
|
||||
// Create the type of `self`.
|
||||
let self_type = build::mk_raw_path(span, ~[ type_ident ]);
|
||||
let self_type = ty_path(self_type, cx.next_id());
|
||||
let self_type = @{ id: cx.next_id(), node: move self_type, span: span };
|
||||
let self_type = create_self_type_with_params(cx,
|
||||
span,
|
||||
type_ident,
|
||||
ty_params);
|
||||
|
||||
// Create the impl item.
|
||||
let impl_item = item_impl(~[],
|
||||
let impl_item = item_impl(move impl_ty_params,
|
||||
Some(trait_ref),
|
||||
self_type,
|
||||
methods.map(|x| *x));
|
||||
@ -191,6 +232,7 @@ fn create_derived_impl(cx: ext_ctxt,
|
||||
fn create_derived_eq_impl(cx: ext_ctxt,
|
||||
span: span,
|
||||
type_ident: ident,
|
||||
+ty_params: ~[ty_param],
|
||||
eq_method: @method,
|
||||
ne_method: @method)
|
||||
-> @item {
|
||||
@ -200,20 +242,22 @@ fn create_derived_eq_impl(cx: ext_ctxt,
|
||||
cx.ident_of(~"cmp"),
|
||||
cx.ident_of(~"Eq")
|
||||
];
|
||||
create_derived_impl(cx, span, type_ident, methods, trait_path)
|
||||
create_derived_impl(cx, span, type_ident, ty_params, methods, trait_path)
|
||||
}
|
||||
|
||||
fn create_derived_iter_bytes_impl(cx: ext_ctxt,
|
||||
span: span,
|
||||
type_ident: ident,
|
||||
+ty_params: ~[ty_param],
|
||||
method: @method)
|
||||
-> @item {
|
||||
let methods = [ method ];
|
||||
let trait_path = [
|
||||
cx.ident_of(~"core"),
|
||||
cx.ident_of(~"to_bytes"),
|
||||
cx.ident_of(~"IterBytes")
|
||||
];
|
||||
create_derived_impl(cx, span, type_ident, [ method ], trait_path)
|
||||
create_derived_impl(cx, span, type_ident, ty_params, methods, trait_path)
|
||||
}
|
||||
|
||||
// Creates a method from the given set of statements conforming to the
|
||||
@ -267,9 +311,9 @@ fn create_iter_bytes_method(cx: ext_ctxt,
|
||||
|
||||
fn create_enum_variant_pattern(cx: ext_ctxt,
|
||||
span: span,
|
||||
variant: &ast::variant,
|
||||
variant: &variant,
|
||||
prefix: ~str)
|
||||
-> @ast::pat {
|
||||
-> @pat {
|
||||
let variant_ident = variant.node.name;
|
||||
match variant.node.kind {
|
||||
tuple_variant_kind(ref variant_args) => {
|
||||
@ -386,7 +430,8 @@ fn variant_arg_count(cx: ext_ctxt, span: span, variant: &variant) -> uint {
|
||||
fn expand_deriving_eq_struct_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
struct_def: &struct_def,
|
||||
type_ident: ident)
|
||||
type_ident: ident,
|
||||
+ty_params: ~[ty_param])
|
||||
-> @item {
|
||||
// Create the methods.
|
||||
let eq_ident = cx.ident_of(~"eq");
|
||||
@ -396,22 +441,63 @@ fn expand_deriving_eq_struct_def(cx: ext_ctxt,
|
||||
struct_def,
|
||||
eq_ident,
|
||||
type_ident,
|
||||
ty_params,
|
||||
Conjunction);
|
||||
let ne_method = expand_deriving_eq_struct_method(cx,
|
||||
span,
|
||||
struct_def,
|
||||
ne_ident,
|
||||
type_ident,
|
||||
ty_params,
|
||||
Disjunction);
|
||||
|
||||
// Create the implementation.
|
||||
return create_derived_eq_impl(cx, span, type_ident, eq_method, ne_method);
|
||||
return create_derived_eq_impl(cx,
|
||||
span,
|
||||
type_ident,
|
||||
move ty_params,
|
||||
eq_method,
|
||||
ne_method);
|
||||
}
|
||||
|
||||
fn expand_deriving_eq_enum_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
enum_definition: &enum_def,
|
||||
type_ident: ident,
|
||||
+ty_params: ~[ty_param])
|
||||
-> @item {
|
||||
// Create the methods.
|
||||
let eq_ident = cx.ident_of(~"eq");
|
||||
let ne_ident = cx.ident_of(~"ne");
|
||||
let eq_method = expand_deriving_eq_enum_method(cx,
|
||||
span,
|
||||
enum_definition,
|
||||
eq_ident,
|
||||
type_ident,
|
||||
ty_params,
|
||||
Conjunction);
|
||||
let ne_method = expand_deriving_eq_enum_method(cx,
|
||||
span,
|
||||
enum_definition,
|
||||
ne_ident,
|
||||
type_ident,
|
||||
ty_params,
|
||||
Disjunction);
|
||||
|
||||
// Create the implementation.
|
||||
return create_derived_eq_impl(cx,
|
||||
span,
|
||||
type_ident,
|
||||
move ty_params,
|
||||
eq_method,
|
||||
ne_method);
|
||||
}
|
||||
|
||||
fn expand_deriving_iter_bytes_struct_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
struct_def: &struct_def,
|
||||
type_ident: ident)
|
||||
type_ident: ident,
|
||||
+ty_params: ~[ty_param])
|
||||
-> @item {
|
||||
// Create the method.
|
||||
let method = expand_deriving_iter_bytes_struct_method(cx,
|
||||
@ -419,13 +505,18 @@ fn expand_deriving_iter_bytes_struct_def(cx: ext_ctxt,
|
||||
struct_def);
|
||||
|
||||
// Create the implementation.
|
||||
return create_derived_iter_bytes_impl(cx, span, type_ident, method);
|
||||
return create_derived_iter_bytes_impl(cx,
|
||||
span,
|
||||
type_ident,
|
||||
move ty_params,
|
||||
method);
|
||||
}
|
||||
|
||||
fn expand_deriving_iter_bytes_enum_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
enum_definition: &enum_def,
|
||||
type_ident: ident)
|
||||
type_ident: ident,
|
||||
+ty_params: ~[ty_param])
|
||||
-> @item {
|
||||
// Create the method.
|
||||
let method = expand_deriving_iter_bytes_enum_method(cx,
|
||||
@ -433,7 +524,11 @@ fn expand_deriving_iter_bytes_enum_def(cx: ext_ctxt,
|
||||
enum_definition);
|
||||
|
||||
// Create the implementation.
|
||||
return create_derived_iter_bytes_impl(cx, span, type_ident, method);
|
||||
return create_derived_iter_bytes_impl(cx,
|
||||
span,
|
||||
type_ident,
|
||||
move ty_params,
|
||||
method);
|
||||
}
|
||||
|
||||
fn expand_deriving_eq_struct_method(cx: ext_ctxt,
|
||||
@ -441,6 +536,7 @@ fn expand_deriving_eq_struct_method(cx: ext_ctxt,
|
||||
struct_def: &struct_def,
|
||||
method_ident: ident,
|
||||
type_ident: ident,
|
||||
ty_params: &[ty_param],
|
||||
junction: Junction)
|
||||
-> @method {
|
||||
let self_ident = cx.ident_of(~"self");
|
||||
@ -483,7 +579,12 @@ fn expand_deriving_eq_struct_method(cx: ext_ctxt,
|
||||
|
||||
// Create the method itself.
|
||||
let body = finish_eq_chain_expr(cx, span, outer_expr, junction);
|
||||
return create_eq_method(cx, span, method_ident, type_ident, body);
|
||||
return create_eq_method(cx,
|
||||
span,
|
||||
method_ident,
|
||||
type_ident,
|
||||
ty_params,
|
||||
body);
|
||||
}
|
||||
|
||||
fn expand_deriving_iter_bytes_struct_method(cx: ext_ctxt,
|
||||
@ -521,36 +622,12 @@ fn expand_deriving_iter_bytes_struct_method(cx: ext_ctxt,
|
||||
return create_iter_bytes_method(cx, span, move statements);
|
||||
}
|
||||
|
||||
fn expand_deriving_eq_enum_def(cx: ext_ctxt,
|
||||
span: span,
|
||||
enum_definition: &enum_def,
|
||||
type_ident: ident)
|
||||
-> @item {
|
||||
// Create the methods.
|
||||
let eq_ident = cx.ident_of(~"eq");
|
||||
let ne_ident = cx.ident_of(~"ne");
|
||||
let eq_method = expand_deriving_eq_enum_method(cx,
|
||||
span,
|
||||
enum_definition,
|
||||
eq_ident,
|
||||
type_ident,
|
||||
Conjunction);
|
||||
let ne_method = expand_deriving_eq_enum_method(cx,
|
||||
span,
|
||||
enum_definition,
|
||||
ne_ident,
|
||||
type_ident,
|
||||
Disjunction);
|
||||
|
||||
// Create the implementation.
|
||||
return create_derived_eq_impl(cx, span, type_ident, eq_method, ne_method);
|
||||
}
|
||||
|
||||
fn expand_deriving_eq_enum_method(cx: ext_ctxt,
|
||||
span: span,
|
||||
enum_definition: &enum_def,
|
||||
method_ident: ident,
|
||||
type_ident: ident,
|
||||
ty_params: &[ty_param],
|
||||
junction: Junction)
|
||||
-> @method {
|
||||
let self_ident = cx.ident_of(~"self");
|
||||
@ -672,6 +749,7 @@ fn expand_deriving_eq_enum_method(cx: ext_ctxt,
|
||||
span,
|
||||
method_ident,
|
||||
type_ident,
|
||||
ty_params,
|
||||
self_match_expr);
|
||||
}
|
||||
|
||||
|
17
src/test/run-pass/deriving-via-extension-type-params.rs
Normal file
17
src/test/run-pass/deriving-via-extension-type-params.rs
Normal file
@ -0,0 +1,17 @@
|
||||
#[deriving_eq]
|
||||
#[deriving_iter_bytes]
|
||||
struct Foo<T> {
|
||||
x: int,
|
||||
y: T,
|
||||
z: int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = Foo { x: 1, y: 2.0, z: 3 };
|
||||
let b = Foo { x: 1, y: 2.0, z: 3 };
|
||||
assert a == b;
|
||||
assert !(a != b);
|
||||
assert a.eq(&b);
|
||||
assert !a.ne(&b);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user