syntax::ext: Make type errors in deriving point to the field itself.

This rearranges the deriving code so that #[deriving] a trait on a field
that doesn't implement that trait will point to the field in question,
e.g.

    struct NotEq; // doesn't implement Eq

    #[deriving(Eq)]
    struct Foo {
        ok: int,
        also_ok: ~str,
        bad: NotEq // error points here.
    }

Unfortunately, this means the error is disconnected from the `deriving`
itself but there's no current way to pass that information through to
rustc except via the spans, at the moment.

Fixes #7724.
This commit is contained in:
Huon Wilson
2013-11-07 18:49:01 +11:00
parent 57d1ed819b
commit 812ea9e169
13 changed files with 410 additions and 312 deletions
+5 -5
View File
@@ -94,21 +94,21 @@ fn cs_clone(
}
match *all_fields {
[(None, _, _), .. _] => {
[FieldInfo { name: None, _ }, .. _] => {
// enum-like
let subcalls = all_fields.map(|&(_, self_f, _)| subcall(self_f));
let subcalls = all_fields.map(|field| subcall(field.self_));
cx.expr_call_ident(span, ctor_ident, subcalls)
},
_ => {
// struct-like
let fields = do all_fields.map |&(o_id, self_f, _)| {
let ident = match o_id {
let fields = do all_fields.map |field| {
let ident = match field.name {
Some(i) => i,
None => cx.span_bug(span,
format!("unnamed field in normal struct in `deriving({})`",
name))
};
cx.field_imm(span, ident, subcall(self_f))
cx.field_imm(span, ident, subcall(field.self_))
};
if fields.is_empty() {
+35 -46
View File
@@ -13,9 +13,7 @@
encodable.rs for more.
*/
use std::vec;
use ast::{MetaItem, item, Expr, MutMutable};
use ast::{MetaItem, item, Expr, MutMutable, Ident};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
@@ -66,37 +64,18 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
return match *substr.fields {
StaticStruct(_, ref summary) => {
let nfields = match *summary {
Left(n) => n, Right(ref fields) => fields.len()
Unnamed(ref fields) => fields.len(),
Named(ref fields) => fields.len()
};
let read_struct_field = cx.ident_of("read_struct_field");
let getarg = |name: @str, field: uint| {
let result = do decode_static_fields(cx, span, substr.type_ident,
summary) |span, name, field| {
cx.expr_method_call(span, blkdecoder, read_struct_field,
~[cx.expr_str(span, name),
cx.expr_uint(span, field),
lambdadecode])
};
let result = match *summary {
Left(n) => {
if n == 0 {
cx.expr_ident(span, substr.type_ident)
} else {
let mut fields = vec::with_capacity(n);
for i in range(0, n) {
fields.push(getarg(format!("_field{}", i).to_managed(), i));
}
cx.expr_call_ident(span, substr.type_ident, fields)
}
}
Right(ref fields) => {
let fields = do fields.iter().enumerate().map |(i, f)| {
cx.field_imm(span, *f, getarg(cx.str_of(*f), i))
}.collect();
cx.expr_struct_ident(span, substr.type_ident, fields)
}
};
cx.expr_method_call(span, decoder, cx.ident_of("read_struct"),
~[cx.expr_str(span, cx.str_of(substr.type_ident)),
cx.expr_uint(span, nfields),
@@ -113,31 +92,13 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
let (name, parts) = match *f { (i, ref p) => (i, p) };
variants.push(cx.expr_str(span, cx.str_of(name)));
let getarg = |field: uint| {
let decoded = do decode_static_fields(cx, span, name,
parts) |span, _, field| {
cx.expr_method_call(span, blkdecoder, rvariant_arg,
~[cx.expr_uint(span, field),
lambdadecode])
};
let decoded = match *parts {
Left(n) => {
if n == 0 {
cx.expr_ident(span, name)
} else {
let mut fields = vec::with_capacity(n);
for i in range(0u, n) {
fields.push(getarg(i));
}
cx.expr_call_ident(span, name, fields)
}
}
Right(ref fields) => {
let fields = do fields.iter().enumerate().map |(i, f)| {
cx.field_imm(span, *f, getarg(i))
}.collect();
cx.expr_struct_ident(span, name, fields)
}
};
arms.push(cx.arm(span,
~[cx.pat_lit(span, cx.expr_uint(span, i))],
decoded));
@@ -158,3 +119,31 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
_ => cx.bug("expected StaticEnum or StaticStruct in deriving(Decodable)")
};
}
/// Create a decoder for a single enum variant/struct:
/// - `outer_pat_ident` is the name of this enum variant/struct
/// - `getarg` should retrieve the `uint`-th field with name `@str`.
fn decode_static_fields(cx: @ExtCtxt, outer_span: Span, outer_pat_ident: Ident,
fields: &StaticFields,
getarg: &fn(Span, @str, uint) -> @Expr) -> @Expr {
match *fields {
Unnamed(ref fields) => {
if fields.is_empty() {
cx.expr_ident(outer_span, outer_pat_ident)
} else {
let fields = do fields.iter().enumerate().map |(i, &span)| {
getarg(span, format!("_field{}", i).to_managed(), i)
}.collect();
cx.expr_call_ident(outer_span, outer_pat_ident, fields)
}
}
Named(ref fields) => {
// use the field's span to get nicer error messages.
let fields = do fields.iter().enumerate().map |(i, &(name, span))| {
cx.field_imm(span, name, getarg(span, cx.str_of(name), i))
}.collect();
cx.expr_struct_ident(outer_span, outer_pat_ident, fields)
}
}
}
+7 -9
View File
@@ -14,8 +14,6 @@
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use std::vec;
pub fn expand_deriving_default(cx: @ExtCtxt,
span: Span,
mitem: @MetaItem,
@@ -47,22 +45,22 @@ fn default_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Exp
cx.ident_of("Default"),
cx.ident_of("default")
];
let default_call = cx.expr_call_global(span, default_ident.clone(), ~[]);
let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ~[]);
return match *substr.fields {
StaticStruct(_, ref summary) => {
match *summary {
Left(count) => {
if count == 0 {
Unnamed(ref fields) => {
if fields.is_empty() {
cx.expr_ident(span, substr.type_ident)
} else {
let exprs = vec::from_elem(count, default_call);
let exprs = fields.map(|sp| default_call(*sp));
cx.expr_call_ident(span, substr.type_ident, exprs)
}
}
Right(ref fields) => {
let default_fields = do fields.map |ident| {
cx.field_imm(span, *ident, default_call)
Named(ref fields) => {
let default_fields = do fields.map |&(ident, span)| {
cx.field_imm(span, ident, default_call(span))
};
cx.expr_struct_ident(span, substr.type_ident, default_fields)
}
+5 -6
View File
@@ -123,11 +123,11 @@ fn encodable_substructure(cx: @ExtCtxt, span: Span,
let emit_struct_field = cx.ident_of("emit_struct_field");
let mut stmts = ~[];
for (i, f) in fields.iter().enumerate() {
let (name, val) = match *f {
(Some(id), e, _) => (cx.str_of(id), e),
(None, e, _) => (format!("_field{}", i).to_managed(), e)
let name = match f.name {
Some(id) => cx.str_of(id),
None => format!("_field{}", i).to_managed()
};
let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]);
let enc = cx.expr_method_call(span, f.self_, encode, ~[blkencoder]);
let lambda = cx.lambda_expr_1(span, enc, blkarg);
let call = cx.expr_method_call(span, blkencoder,
emit_struct_field,
@@ -154,8 +154,7 @@ fn encodable_substructure(cx: @ExtCtxt, span: Span,
let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
let mut stmts = ~[];
for (i, f) in fields.iter().enumerate() {
let val = match *f { (_, e, _) => e };
let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]);
let enc = cx.expr_method_call(span, f.self_, encode, ~[blkencoder]);
let lambda = cx.lambda_expr_1(span, enc, blkarg);
let call = cx.expr_method_call(span, blkencoder,
emit_variant_arg,
+252 -219
View File
@@ -59,7 +59,7 @@
an identifier in the source code. For example, the `x`s in the
following snippet
```
~~~
struct A { x : int }
struct B(int);
@@ -72,17 +72,17 @@ enum C {
The `int`s in `B` and `C0` don't have an identifier, so the
`Option<ident>`s would be `None` for them.
In the static cases, the structure is summarised, either into the
number of fields or a list of field idents (for tuple structs and
record structs, respectively), or a list of these, for enums (one for
each variant). For empty struct and empty enum variants, it is
represented as a count of 0.
In the static cases, the structure is summarised, either into the just
spans of the fields or a list of spans and the field idents (for tuple
structs and record structs, respectively), or a list of these, for
enums (one for each variant). For empty struct and empty enum
variants, it is represented as a count of 0.
# Examples
The following simplified `Eq` is used for in-code examples:
```
~~~
trait Eq {
fn eq(&self, other: &Self);
}
@@ -91,7 +91,7 @@ fn eq(&self, other: &int) -> bool {
*self == *other
}
}
```
~~~
Some examples of the values of `SubstructureFields` follow, using the
above `Eq`, `A`, `B` and `C`.
@@ -100,50 +100,62 @@ fn eq(&self, other: &int) -> bool {
When generating the `expr` for the `A` impl, the `SubstructureFields` is
```
Struct(~[(Some(<ident of x>),
<expr for &self.x>,
~[<expr for &other.x])])
```
~~~
Struct(~[FieldInfo {
span: <span of x>
name: Some(<ident of x>),
self_: <expr for &self.x>,
other: ~[<expr for &other.x]
}])
~~~
For the `B` impl, called with `B(a)` and `B(b)`,
```
Struct(~[(None,
~~~
Struct(~[FieldInfo {
span: <span of `int`>,
name: None,
<expr for &a>
~[<expr for &b>])])
```
~[<expr for &b>]
}])
~~~
## Enums
When generating the `expr` for a call with `self == C0(a)` and `other
== C0(b)`, the SubstructureFields is
```
~~~
EnumMatching(0, <ast::variant for C0>,
~[None,
<expr for &a>,
~[<expr for &b>]])
```
~[FieldInfo {
span: <span of int>
name: None,
self_: <expr for &a>,
other: ~[<expr for &b>]
}])
~~~
For `C1 {x}` and `C1 {x}`,
```
~~~
EnumMatching(1, <ast::variant for C1>,
~[Some(<ident of x>),
<expr for &self.x>,
~[<expr for &other.x>]])
```
~[FieldInfo {
span: <span of x>
name: Some(<ident of x>),
self_: <expr for &self.x>,
other: ~[<expr for &other.x>]
}])
~~~
For `C0(a)` and `C1 {x}` ,
```
~~~
EnumNonMatching(~[(0, <ast::variant for B0>,
~[(None, <expr for &a>)]),
~[(<span of int>, None, <expr for &a>)]),
(1, <ast::variant for B1>,
~[(Some(<ident of x>),
~[(<span of x>, Some(<ident of x>),
<expr for &other.x>)])])
```
~~~
(and vice versa, but with the order of the outermost list flipped.)
@@ -152,13 +164,13 @@ fn eq(&self, other: &int) -> bool {
A static method on the above would result in,
~~~~
StaticStruct(<ast::struct_def of A>, Right(~[<ident of x>]))
StaticStruct(<ast::struct_def of A>, Named(~[(<ident of x>, <span of x>)]))
StaticStruct(<ast::struct_def of B>, Left(1))
StaticStruct(<ast::struct_def of B>, Unnamed(~[<span of x>]))
StaticEnum(<ast::enum_def of C>, ~[(<ident of C0>, Left(1)),
(<ident of C1>, Right(~[<ident of x>]))])
```
StaticEnum(<ast::enum_def of C>, ~[(<ident of C0>, Unnamed(~[<span of int>])),
(<ident of C1>, Named(~[(<ident of x>, <span of x>)]))])
~~~
*/
@@ -226,34 +238,50 @@ pub struct Substructure<'self> {
fields: &'self SubstructureFields<'self>
}
/// Summary of the relevant parts of a struct/enum field.
pub struct FieldInfo {
span: Span,
/// None for tuple structs/normal enum variants, Some for normal
/// structs/struct enum variants.
name: Option<Ident>,
/// The expression corresponding to this field of `self`
/// (specifically, a reference to it).
self_: @Expr,
/// The expressions corresponding to references to this field in
/// the other Self arguments.
other: ~[@Expr]
}
/// Fields for a static method
pub enum StaticFields {
/// Tuple structs/enum variants like this
Unnamed(~[Span]),
/// Normal structs/struct variants.
Named(~[(Ident, Span)])
}
/// A summary of the possible sets of fields. See above for details
/// and examples
pub enum SubstructureFields<'self> {
/**
Vec of `(field ident, self_or_other)` where the field
ident is the ident of the current field (`None` for all fields in tuple
structs).
*/
Struct(~[(Option<Ident>, @Expr, ~[@Expr])]),
Struct(~[FieldInfo]),
/**
Matching variants of the enum: variant index, ast::variant,
fields: `(field ident, self, [others])`, where the field ident is
only non-`None` in the case of a struct variant.
fields: the field name is only non-`None` in the case of a struct
variant.
*/
EnumMatching(uint, &'self ast::variant, ~[(Option<Ident>, @Expr, ~[@Expr])]),
EnumMatching(uint, &'self ast::variant, ~[FieldInfo]),
/**
non-matching variants of the enum, [(variant index, ast::variant,
[field ident, fields])] (i.e. all fields for self are in the
[field span, field ident, fields])] (i.e. all fields for self are in the
first tuple, for other1 are in the second tuple, etc.)
*/
EnumNonMatching(&'self [(uint, ast::variant, ~[(Option<Ident>, @Expr)])]),
EnumNonMatching(&'self [(uint, ast::variant, ~[(Span, Option<Ident>, @Expr)])]),
/// A static method where Self is a struct
StaticStruct(&'self ast::struct_def, Either<uint, ~[Ident]>),
/// A static method where Self is an enum
StaticEnum(&'self ast::enum_def, ~[(Ident, Either<uint, ~[Ident]>)])
/// A static method where Self is a struct.
StaticStruct(&'self ast::struct_def, StaticFields),
/// A static method where Self is an enum.
StaticEnum(&'self ast::enum_def, ~[(Ident, StaticFields)])
}
@@ -273,13 +301,13 @@ pub enum SubstructureFields<'self> {
pub type EnumNonMatchFunc<'self> =
&'self fn(@ExtCtxt, Span,
&[(uint, ast::variant,
~[(Option<Ident>, @Expr)])],
~[(Span, Option<Ident>, @Expr)])],
&[@Expr]) -> @Expr;
impl<'self> TraitDef<'self> {
pub fn expand(&self, cx: @ExtCtxt,
span: Span,
trait_span: Span,
_mitem: @ast::MetaItem,
in_items: ~[@ast::item]) -> ~[@ast::item] {
let mut result = ~[];
@@ -287,13 +315,13 @@ pub fn expand(&self, cx: @ExtCtxt,
result.push(*item);
match item.node {
ast::item_struct(struct_def, ref generics) => {
result.push(self.expand_struct_def(cx, span,
result.push(self.expand_struct_def(cx, trait_span,
struct_def,
item.ident,
generics));
}
ast::item_enum(ref enum_def, ref generics) => {
result.push(self.expand_enum_def(cx, span,
result.push(self.expand_enum_def(cx, trait_span,
enum_def,
item.ident,
generics));
@@ -314,12 +342,12 @@ pub fn expand(&self, cx: @ExtCtxt,
* where B1, B2, ... are the bounds given by `bounds_paths`.'
*
*/
fn create_derived_impl(&self, cx: @ExtCtxt, span: Span,
fn create_derived_impl(&self, cx: @ExtCtxt, trait_span: Span,
type_ident: Ident, generics: &Generics,
methods: ~[@ast::method]) -> @ast::item {
let trait_path = self.path.to_path(cx, span, type_ident, generics);
let trait_path = self.path.to_path(cx, trait_span, type_ident, generics);
let mut trait_generics = self.generics.to_generics(cx, span, type_ident, generics);
let mut trait_generics = self.generics.to_generics(cx, trait_span, type_ident, generics);
// Copy the lifetimes
for l in generics.lifetimes.iter() {
trait_generics.lifetimes.push(*l)
@@ -331,7 +359,7 @@ fn create_derived_impl(&self, cx: @ExtCtxt, span: Span,
let mut bounds = opt_vec::from(
// extra restrictions on the generics parameters to the type being derived upon
do self.additional_bounds.map |p| {
cx.typarambound(p.to_path(cx, span, type_ident, generics))
cx.typarambound(p.to_path(cx, trait_span, type_ident, generics))
});
// require the current trait
bounds.push(cx.typarambound(trait_path.clone()));
@@ -344,7 +372,7 @@ fn create_derived_impl(&self, cx: @ExtCtxt, span: Span,
// Create the type parameters on the `self` path.
let self_ty_params = do generics.ty_params.map |ty_param| {
cx.ty_ident(span, ty_param.ident)
cx.ty_ident(trait_span, ty_param.ident)
};
let self_lifetime = if generics.lifetimes.is_empty() {
@@ -354,16 +382,16 @@ fn create_derived_impl(&self, cx: @ExtCtxt, span: Span,
};
// Create the type of `self`.
let self_type = cx.ty_path(cx.path_all(span, false, ~[ type_ident ], self_lifetime,
let self_type = cx.ty_path(cx.path_all(trait_span, false, ~[ type_ident ], self_lifetime,
opt_vec::take_vec(self_ty_params)), None);
let doc_attr = cx.attribute(
span,
cx.meta_name_value(span,
trait_span,
cx.meta_name_value(trait_span,
@"doc",
ast::lit_str(@"Automatically derived.", ast::CookedStr)));
cx.item(
span,
trait_span,
::parse::token::special_idents::clownshoes_extensions,
~[doc_attr],
ast::item_impl(trait_generics,
@@ -373,72 +401,72 @@ fn create_derived_impl(&self, cx: @ExtCtxt, span: Span,
}
fn expand_struct_def(&self, cx: @ExtCtxt,
span: Span,
trait_span: Span,
struct_def: &struct_def,
type_ident: Ident,
generics: &Generics) -> @ast::item {
let methods = do self.methods.map |method_def| {
let (explicit_self, self_args, nonself_args, tys) =
method_def.split_self_nonself_args(cx, span, type_ident, generics);
method_def.split_self_nonself_args(cx, trait_span, type_ident, generics);
let body = if method_def.is_static() {
method_def.expand_static_struct_method_body(
cx, span,
cx, trait_span,
struct_def,
type_ident,
self_args, nonself_args)
} else {
method_def.expand_struct_method_body(cx, span,
method_def.expand_struct_method_body(cx, trait_span,
struct_def,
type_ident,
self_args, nonself_args)
};
method_def.create_method(cx, span,
method_def.create_method(cx, trait_span,
type_ident, generics,
explicit_self, tys,
body)
};
self.create_derived_impl(cx, span, type_ident, generics, methods)
self.create_derived_impl(cx, trait_span, type_ident, generics, methods)
}
fn expand_enum_def(&self,
cx: @ExtCtxt, span: Span,
cx: @ExtCtxt, trait_span: Span,
enum_def: &enum_def,
type_ident: Ident,
generics: &Generics) -> @ast::item {
let methods = do self.methods.map |method_def| {
let (explicit_self, self_args, nonself_args, tys) =
method_def.split_self_nonself_args(cx, span, type_ident, generics);
method_def.split_self_nonself_args(cx, trait_span, type_ident, generics);
let body = if method_def.is_static() {
method_def.expand_static_enum_method_body(
cx, span,
cx, trait_span,
enum_def,
type_ident,
self_args, nonself_args)
} else {
method_def.expand_enum_method_body(cx, span,
method_def.expand_enum_method_body(cx, trait_span,
enum_def,
type_ident,
self_args, nonself_args)
};
method_def.create_method(cx, span,
method_def.create_method(cx, trait_span,
type_ident, generics,
explicit_self, tys,
body)
};
self.create_derived_impl(cx, span, type_ident, generics, methods)
self.create_derived_impl(cx, trait_span, type_ident, generics, methods)
}
}
impl<'self> MethodDef<'self> {
fn call_substructure_method(&self,
cx: @ExtCtxt,
span: Span,
trait_span: Span,
type_ident: Ident,
self_args: &[@Expr],
nonself_args: &[@Expr],
@@ -451,21 +479,21 @@ fn call_substructure_method(&self,
nonself_args: nonself_args,
fields: fields
};
(self.combine_substructure)(cx, span,
(self.combine_substructure)(cx, trait_span,
&substructure)
}
fn get_ret_ty(&self, cx: @ExtCtxt, span: Span,
generics: &Generics, type_ident: Ident) -> ast::Ty {
self.ret_ty.to_ty(cx, span, type_ident, generics)
fn get_ret_ty(&self, cx: @ExtCtxt, trait_span: Span,
generics: &Generics, type_ident: Ident) -> ast::Ty {
self.ret_ty.to_ty(cx, trait_span, type_ident, generics)
}
fn is_static(&self) -> bool {
self.explicit_self.is_none()
}
fn split_self_nonself_args(&self, cx: @ExtCtxt, span: Span,
type_ident: Ident, generics: &Generics)
fn split_self_nonself_args(&self, cx: @ExtCtxt, trait_span: Span,
type_ident: Ident, generics: &Generics)
-> (ast::explicit_self, ~[@Expr], ~[@Expr], ~[(Ident, ast::Ty)]) {
let mut self_args = ~[];
@@ -475,22 +503,22 @@ fn split_self_nonself_args(&self, cx: @ExtCtxt, span: Span,
let ast_explicit_self = match self.explicit_self {
Some(ref self_ptr) => {
let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
let (self_expr, explicit_self) = ty::get_explicit_self(cx, trait_span, self_ptr);
self_args.push(self_expr);
nonstatic = true;
explicit_self
}
None => respan(span, ast::sty_static),
None => respan(trait_span, ast::sty_static),
};
for (i, ty) in self.args.iter().enumerate() {
let ast_ty = ty.to_ty(cx, span, type_ident, generics);
let ast_ty = ty.to_ty(cx, trait_span, type_ident, generics);
let ident = cx.ident_of(format!("__arg_{}", i));
arg_tys.push((ident, ast_ty));
let arg_expr = cx.expr_ident(span, ident);
let arg_expr = cx.expr_ident(trait_span, ident);
match *ty {
// for static methods, just treat any Self
@@ -499,7 +527,7 @@ fn split_self_nonself_args(&self, cx: @ExtCtxt, span: Span,
self_args.push(arg_expr);
}
Ptr(~Self, _) if nonstatic => {
self_args.push(cx.expr_deref(span, arg_expr))
self_args.push(cx.expr_deref(trait_span, arg_expr))
}
_ => {
nonself_args.push(arg_expr);
@@ -510,20 +538,20 @@ fn split_self_nonself_args(&self, cx: @ExtCtxt, span: Span,
(ast_explicit_self, self_args, nonself_args, arg_tys)
}
fn create_method(&self, cx: @ExtCtxt, span: Span,
fn create_method(&self, cx: @ExtCtxt, trait_span: Span,
type_ident: Ident,
generics: &Generics,
explicit_self: ast::explicit_self,
arg_types: ~[(Ident, ast::Ty)],
body: @Expr) -> @ast::method {
// create the generics that aren't for Self
let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
let fn_generics = self.generics.to_generics(cx, trait_span, type_ident, generics);
let args = do arg_types.map |pair| {
cx.arg(span, pair.first(), pair.second())
};
let args = do arg_types.move_iter().map |(name, ty)| {
cx.arg(trait_span, name, ty)
}.collect();
let ret_type = self.get_ret_ty(cx, span, generics, type_ident);
let ret_type = self.get_ret_ty(cx, trait_span, generics, type_ident);
let method_ident = cx.ident_of(self.name);
let fn_decl = cx.fn_decl(args, ret_type);
@@ -540,14 +568,14 @@ fn create_method(&self, cx: @ExtCtxt, span: Span,
decl: fn_decl,
body: body_block,
id: ast::DUMMY_NODE_ID,
span: span,
span: trait_span,
self_id: ast::DUMMY_NODE_ID,
vis: ast::inherited,
}
}
/**
```
~~~
#[deriving(Eq)]
struct A { x: int, y: int }
@@ -565,11 +593,11 @@ fn eq(&self, __arg_1: &A) -> bool {
}
}
}
```
~~~
*/
fn expand_struct_method_body(&self,
cx: @ExtCtxt,
span: Span,
trait_span: Span,
struct_def: &struct_def,
type_ident: Ident,
self_args: &[@Expr],
@@ -580,7 +608,7 @@ fn expand_struct_method_body(&self,
// [fields of next Self arg], [etc]]
let mut patterns = ~[];
for i in range(0u, self_args.len()) {
let (pat, ident_expr) = create_struct_pattern(cx, span,
let (pat, ident_expr) = create_struct_pattern(cx, trait_span,
type_ident, struct_def,
format!("__self_{}", i),
ast::MutImmutable);
@@ -591,22 +619,27 @@ fn expand_struct_method_body(&self,
// transpose raw_fields
let fields = match raw_fields {
[ref self_arg, .. rest] => {
do self_arg.iter().enumerate().map |(i, &(opt_id, field))| {
do self_arg.iter().enumerate().map |(i, &(span, opt_id, field))| {
let other_fields = do rest.map |l| {
match &l[i] {
&(_, ex) => ex
&(_, _, ex) => ex
}
};
(opt_id, field, other_fields)
FieldInfo {
span: span,
name: opt_id,
self_: field,
other: other_fields
}
}.collect()
}
[] => { cx.span_bug(span, "No self arguments to non-static \
[] => { cx.span_bug(trait_span, "No self arguments to non-static \
method in generic `deriving`") }
};
// body of the inner most destructuring match
let mut body = self.call_substructure_method(
cx, span,
cx, trait_span,
type_ident,
self_args,
nonself_args,
@@ -616,30 +649,30 @@ fn expand_struct_method_body(&self,
// structs. This is actually right-to-left, but it shoudn't
// matter.
for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) {
body = cx.expr_match(span, arg_expr,
~[ cx.arm(span, ~[pat], body) ])
body = cx.expr_match(trait_span, arg_expr,
~[ cx.arm(trait_span, ~[pat], body) ])
}
body
}
fn expand_static_struct_method_body(&self,
cx: @ExtCtxt,
span: Span,
trait_span: Span,
struct_def: &struct_def,
type_ident: Ident,
self_args: &[@Expr],
nonself_args: &[@Expr])
-> @Expr {
let summary = summarise_struct(cx, span, struct_def);
let summary = summarise_struct(cx, trait_span, struct_def);
self.call_substructure_method(cx, span,
self.call_substructure_method(cx, trait_span,
type_ident,
self_args, nonself_args,
&StaticStruct(struct_def, summary))
}
/**
```
~~~
#[deriving(Eq)]
enum A {
A1
@@ -662,18 +695,18 @@ fn eq(&self, __arg_1: &A) {
}
}
}
```
~~~
*/
fn expand_enum_method_body(&self,
cx: @ExtCtxt,
span: Span,
trait_span: Span,
enum_def: &enum_def,
type_ident: Ident,
self_args: &[@Expr],
nonself_args: &[@Expr])
-> @Expr {
let mut matches = ~[];
self.build_enum_match(cx, span, enum_def, type_ident,
self.build_enum_match(cx, trait_span, enum_def, type_ident,
self_args, nonself_args,
None, &mut matches, 0)
}
@@ -682,13 +715,13 @@ fn expand_enum_method_body(&self,
/**
Creates the nested matches for an enum definition recursively, i.e.
```
~~~
match self {
Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
...
}
```
~~~
It acts in the most naive way, so every branch (and subbranch,
subsubbranch, etc) exists, not just the ones where all the variants in
@@ -701,20 +734,20 @@ fn expand_enum_method_body(&self,
the first call).
*/
fn build_enum_match(&self,
cx: @ExtCtxt, span: Span,
cx: @ExtCtxt, trait_span: Span,
enum_def: &enum_def,
type_ident: Ident,
self_args: &[@Expr],
nonself_args: &[@Expr],
matching: Option<uint>,
matches_so_far: &mut ~[(uint, ast::variant,
~[(Option<Ident>, @Expr)])],
~[(Span, Option<Ident>, @Expr)])],
match_count: uint) -> @Expr {
if match_count == self_args.len() {
// we've matched against all arguments, so make the final
// expression at the bottom of the match tree
if matches_so_far.len() == 0 {
cx.span_bug(span, "no self match on an enum in generic \
cx.span_bug(trait_span, "no self match on an enum in generic \
`deriving`");
}
// we currently have a vec of vecs, where each
@@ -742,8 +775,8 @@ fn build_enum_match(&self,
for triple in matches_so_far.tail().iter() {
match triple {
&(_, _, ref other_fields) => {
for (i, pair) in other_fields.iter().enumerate() {
enum_matching_fields[i].push(pair.second());
for (i, &(_, _, e)) in other_fields.iter().enumerate() {
enum_matching_fields[i].push(e);
}
}
}
@@ -751,8 +784,13 @@ fn build_enum_match(&self,
let field_tuples =
do self_vec.iter()
.zip(enum_matching_fields.iter())
.map |(&(id, self_f), other)| {
(id, self_f, (*other).clone())
.map |(&(span, id, self_f), other)| {
FieldInfo {
span: span,
name: id,
self_: self_f,
other: (*other).clone()
}
}.collect();
substructure = EnumMatching(variant_index, variant, field_tuples);
}
@@ -760,7 +798,7 @@ fn build_enum_match(&self,
substructure = EnumNonMatching(*matches_so_far);
}
}
self.call_substructure_method(cx, span, type_ident,
self.call_substructure_method(cx, trait_span, type_ident,
self_args, nonself_args,
&substructure)
@@ -779,13 +817,14 @@ fn build_enum_match(&self,
// make a matching-variant match, and a _ match.
let index = match matching {
Some(i) => i,
None => cx.span_bug(span, "Non-matching variants when required to \
be matching in generic `deriving`")
None => cx.span_bug(trait_span,
"Non-matching variants when required to \
be matching in generic `deriving`")
};
// matching-variant match
let variant = &enum_def.variants[index];
let (pattern, idents) = create_enum_variant_pattern(cx, span,
let (pattern, idents) = create_enum_variant_pattern(cx,
variant,
current_match_str,
ast::MutImmutable);
@@ -793,7 +832,7 @@ fn build_enum_match(&self,
matches_so_far.push((index,
/*bad*/ (*variant).clone(),
idents));
let arm_expr = self.build_enum_match(cx, span,
let arm_expr = self.build_enum_match(cx, trait_span,
enum_def,
type_ident,
self_args, nonself_args,
@@ -801,25 +840,25 @@ fn build_enum_match(&self,
matches_so_far,
match_count + 1);
matches_so_far.pop();
arms.push(cx.arm(span, ~[ pattern ], arm_expr));
arms.push(cx.arm(trait_span, ~[ pattern ], arm_expr));
if enum_def.variants.len() > 1 {
let e = &EnumNonMatching(&[]);
let wild_expr = self.call_substructure_method(cx, span, type_ident,
let wild_expr = self.call_substructure_method(cx, trait_span, type_ident,
self_args, nonself_args,
e);
let wild_arm = cx.arm(span,
~[ cx.pat_wild(span) ],
let wild_arm = cx.arm(trait_span,
~[ cx.pat_wild(trait_span) ],
wild_expr);
arms.push(wild_arm);
}
} else {
// create an arm matching on each variant
for (index, variant) in enum_def.variants.iter().enumerate() {
let (pattern, idents) = create_enum_variant_pattern(cx, span,
variant,
current_match_str,
ast::MutImmutable);
let (pattern, idents) = create_enum_variant_pattern(cx,
variant,
current_match_str,
ast::MutImmutable);
matches_so_far.push((index,
/*bad*/ (*variant).clone(),
@@ -830,7 +869,7 @@ fn build_enum_match(&self,
Some(i) if index == i => Some(i),
_ => None
};
let arm_expr = self.build_enum_match(cx, span,
let arm_expr = self.build_enum_match(cx, trait_span,
enum_def,
type_ident,
self_args, nonself_args,
@@ -839,70 +878,69 @@ fn build_enum_match(&self,
match_count + 1);
matches_so_far.pop();
let arm = cx.arm(span, ~[ pattern ], arm_expr);
let arm = cx.arm(trait_span, ~[ pattern ], arm_expr);
arms.push(arm);
}
}
// match foo { arm, arm, arm, ... }
cx.expr_match(span, self_args[match_count], arms)
cx.expr_match(trait_span, self_args[match_count], arms)
}
}
fn expand_static_enum_method_body(&self,
cx: @ExtCtxt,
span: Span,
enum_def: &enum_def,
type_ident: Ident,
self_args: &[@Expr],
nonself_args: &[@Expr])
cx: @ExtCtxt,
trait_span: Span,
enum_def: &enum_def,
type_ident: Ident,
self_args: &[@Expr],
nonself_args: &[@Expr])
-> @Expr {
let summary = do enum_def.variants.map |v| {
let ident = v.node.name;
let summary = match v.node.kind {
ast::tuple_variant_kind(ref args) => Left(args.len()),
ast::tuple_variant_kind(ref args) => Unnamed(args.map(|va| va.ty.span)),
ast::struct_variant_kind(struct_def) => {
summarise_struct(cx, span, struct_def)
summarise_struct(cx, trait_span, struct_def)
}
};
(ident, summary)
};
self.call_substructure_method(cx,
span, type_ident,
trait_span, type_ident,
self_args, nonself_args,
&StaticEnum(enum_def, summary))
}
}
fn summarise_struct(cx: @ExtCtxt, span: Span,
struct_def: &struct_def) -> Either<uint, ~[Ident]> {
fn summarise_struct(cx: @ExtCtxt, trait_span: Span,
struct_def: &struct_def) -> StaticFields {
let mut named_idents = ~[];
let mut unnamed_count = 0;
let mut just_spans = ~[];
for field in struct_def.fields.iter() {
match field.node.kind {
ast::named_field(ident, _) => named_idents.push(ident),
ast::unnamed_field => unnamed_count += 1,
ast::named_field(ident, _) => named_idents.push((ident, field.span)),
ast::unnamed_field => just_spans.push(field.span),
}
}
match (unnamed_count > 0, named_idents.is_empty()) {
(true, false) => cx.span_bug(span,
"A struct with named and unnamed \
match (just_spans.is_empty(), named_idents.is_empty()) {
(false, false) => cx.span_bug(trait_span,
"A struct with named and unnamed \
fields in generic `deriving`"),
// named fields
(_, false) => Right(named_idents),
(_, false) => Named(named_idents),
// tuple structs (includes empty structs)
(_, _) => Left(unnamed_count)
(_, _) => Unnamed(just_spans)
}
}
pub fn create_subpatterns(cx: @ExtCtxt,
span: Span,
field_paths: ~[ast::Path],
mutbl: ast::Mutability)
-> ~[@ast::Pat] {
do field_paths.map |path| {
cx.pat(span,
cx.pat(path.span,
ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
}
}
@@ -913,20 +951,20 @@ enum StructType {
}
fn create_struct_pattern(cx: @ExtCtxt,
span: Span,
struct_ident: Ident,
struct_def: &struct_def,
prefix: &str,
mutbl: ast::Mutability)
-> (@ast::Pat, ~[(Option<Ident>, @Expr)]) {
trait_span: Span,
struct_ident: Ident,
struct_def: &struct_def,
prefix: &str,
mutbl: ast::Mutability)
-> (@ast::Pat, ~[(Span, Option<Ident>, @Expr)]) {
if struct_def.fields.is_empty() {
return (
cx.pat_ident_binding_mode(
span, struct_ident, ast::BindByValue(ast::MutImmutable)),
trait_span, struct_ident, ast::BindByValue(ast::MutImmutable)),
~[]);
}
let matching_path = cx.path(span, ~[ struct_ident ]);
let matching_path = cx.path(trait_span, ~[ struct_ident ]);
let mut paths = ~[];
let mut ident_expr = ~[];
@@ -945,68 +983,67 @@ fn create_struct_pattern(cx: @ExtCtxt,
None
}
_ => {
cx.span_bug(span, "A struct with named and unnamed fields in `deriving`");
cx.span_bug(struct_field.span,
"A struct with named and unnamed fields in `deriving`");
}
};
let path = cx.path_ident(span,
let path = cx.path_ident(struct_field.span,
cx.ident_of(format!("{}_{}", prefix, i)));
paths.push(path.clone());
ident_expr.push((opt_id, cx.expr_path(path)));
ident_expr.push((struct_field.span, opt_id, cx.expr_path(path)));
}
let subpats = create_subpatterns(cx, span, paths, mutbl);
let subpats = create_subpatterns(cx, 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(None) |push| {
for (&pat, &(id, _)) in subpats.iter().zip(ident_expr.iter()) {
// id is guaranteed to be Some
push(ast::FieldPat { ident: id.unwrap(), pat: pat })
}
};
cx.pat_struct(span, matching_path, field_pats)
let field_pats = do subpats.iter().zip(ident_expr.iter()).map |(&pat, &(_, id, _))| {
// id is guaranteed to be Some
ast::FieldPat { ident: id.unwrap(), pat: pat }
}.collect();
cx.pat_struct(trait_span, matching_path, field_pats)
} else {
cx.pat_enum(span, matching_path, subpats)
cx.pat_enum(trait_span, matching_path, subpats)
};
(pattern, ident_expr)
}
fn create_enum_variant_pattern(cx: @ExtCtxt,
span: Span,
variant: &ast::variant,
prefix: &str,
mutbl: ast::Mutability)
-> (@ast::Pat, ~[(Option<Ident>, @Expr)]) {
variant: &ast::variant,
prefix: &str,
mutbl: ast::Mutability)
-> (@ast::Pat, ~[(Span, Option<Ident>, @Expr)]) {
let variant_ident = variant.node.name;
match variant.node.kind {
ast::tuple_variant_kind(ref variant_args) => {
if variant_args.is_empty() {
return (cx.pat_ident_binding_mode(
span, variant_ident, ast::BindByValue(ast::MutImmutable)), ~[]);
return (cx.pat_ident_binding_mode(variant.span, variant_ident,
ast::BindByValue(ast::MutImmutable)),
~[]);
}
let matching_path = cx.path_ident(span, variant_ident);
let matching_path = cx.path_ident(variant.span, variant_ident);
let mut paths = ~[];
let mut ident_expr = ~[];
for i in range(0u, variant_args.len()) {
let path = cx.path_ident(span,
for (i, va) in variant_args.iter().enumerate() {
let path = cx.path_ident(va.ty.span,
cx.ident_of(format!("{}_{}", prefix, i)));
paths.push(path.clone());
ident_expr.push((None, cx.expr_path(path)));
ident_expr.push((va.ty.span, None, cx.expr_path(path)));
}
let subpats = create_subpatterns(cx, span, paths, mutbl);
let subpats = create_subpatterns(cx, paths, mutbl);
(cx.pat_enum(span, matching_path, subpats),
(cx.pat_enum(variant.span, matching_path, subpats),
ident_expr)
}
ast::struct_variant_kind(struct_def) => {
create_struct_pattern(cx, span,
create_struct_pattern(cx, variant.span,
variant_ident, struct_def,
prefix,
mutbl)
@@ -1029,27 +1066,25 @@ pub fn cs_fold(use_foldl: bool,
other_fs: &[@Expr]) -> @Expr,
base: @Expr,
enum_nonmatch_f: EnumNonMatchFunc,
cx: @ExtCtxt, span: Span,
cx: @ExtCtxt, trait_span: Span,
substructure: &Substructure) -> @Expr {
match *substructure.fields {
EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
if use_foldl {
do all_fields.iter().fold(base) |old, triple| {
let (_, self_f, other_fs) = (*triple).clone();
f(cx, span, old, self_f, other_fs)
do all_fields.iter().fold(base) |old, field| {
f(cx, field.span, old, field.self_, field.other)
}
} else {
do all_fields.rev_iter().fold(base) |old, triple| {
let (_, self_f, other_fs) = (*triple).clone();
f(cx, span, old, self_f, other_fs)
do all_fields.rev_iter().fold(base) |old, field| {
f(cx, field.span, old, field.self_, field.other)
}
}
},
EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, span,
EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
*all_enums,
substructure.nonself_args),
StaticEnum(*) | StaticStruct(*) => {
cx.span_bug(span, "Static function in `deriving`")
cx.span_bug(trait_span, "Static function in `deriving`")
}
}
}
@@ -1059,34 +1094,33 @@ pub fn cs_fold(use_foldl: bool,
Call the method that is being derived on all the fields, and then
process the collected results. i.e.
```
~~~
f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
self_2.method(__arg_1_2, __arg_2_2)])
```
~~~
*/
#[inline]
pub fn cs_same_method(f: &fn(@ExtCtxt, Span, ~[@Expr]) -> @Expr,
enum_nonmatch_f: EnumNonMatchFunc,
cx: @ExtCtxt, span: Span,
cx: @ExtCtxt, trait_span: Span,
substructure: &Substructure) -> @Expr {
match *substructure.fields {
EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
// call self_n.method(other_1_n, other_2_n, ...)
let called = do all_fields.map |triple| {
let (_, self_field, other_fields) = (*triple).clone();
cx.expr_method_call(span,
self_field,
let called = do all_fields.map |field| {
cx.expr_method_call(field.span,
field.self_,
substructure.method_ident,
other_fields)
field.other.clone())
};
f(cx, span, called)
f(cx, trait_span, called)
},
EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, span,
EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
*all_enums,
substructure.nonself_args),
StaticEnum(*) | StaticStruct(*) => {
cx.span_bug(span, "Static function in `deriving`")
cx.span_bug(trait_span, "Static function in `deriving`")
}
}
}
@@ -1101,7 +1135,7 @@ pub fn cs_same_method_fold(use_foldl: bool,
f: &fn(@ExtCtxt, Span, @Expr, @Expr) -> @Expr,
base: @Expr,
enum_nonmatch_f: EnumNonMatchFunc,
cx: @ExtCtxt, span: Span,
cx: @ExtCtxt, trait_span: Span,
substructure: &Substructure) -> @Expr {
cs_same_method(
|cx, span, vals| {
@@ -1116,8 +1150,7 @@ pub fn cs_same_method_fold(use_foldl: bool,
}
},
enum_nonmatch_f,
cx, span, substructure)
cx, trait_span, substructure)
}
/**
@@ -1127,7 +1160,7 @@ pub fn cs_same_method_fold(use_foldl: bool,
#[inline]
pub fn cs_binop(binop: ast::BinOp, base: @Expr,
enum_nonmatch_f: EnumNonMatchFunc,
cx: @ExtCtxt, span: Span,
cx: @ExtCtxt, trait_span: Span,
substructure: &Substructure) -> @Expr {
cs_same_method_fold(
true, // foldl is good enough
@@ -1139,7 +1172,7 @@ pub fn cs_binop(binop: ast::BinOp, base: @Expr,
},
base,
enum_nonmatch_f,
cx, span, substructure)
cx, trait_span, substructure)
}
/// cs_binop with binop == or
+2 -2
View File
@@ -81,8 +81,8 @@ fn iter_bytes_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @
_ => cx.span_bug(span, "Impossible substructure in `deriving(IterBytes)`")
}
for &(_, field, _) in fields.iter() {
exprs.push(call_iterbytes(field));
for &FieldInfo { self_, _ } in fields.iter() {
exprs.push(call_iterbytes(self_));
}
if exprs.len() == 0 {
+10 -12
View File
@@ -15,8 +15,6 @@
use ext::build::{AstBuilder};
use ext::deriving::generic::*;
use std::vec;
pub fn expand_deriving_rand(cx: @ExtCtxt,
span: Span,
mitem: @MetaItem,
@@ -59,7 +57,7 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
cx.ident_of("Rand"),
cx.ident_of("rand")
];
let rand_call = || {
let rand_call = |span| {
cx.expr_call_global(span,
rand_ident.clone(),
~[ rng[0] ])
@@ -112,7 +110,7 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
(ident, ref summary) => {
cx.arm(span,
~[ pat ],
rand_thing(cx, span, ident, summary, || rand_call()))
rand_thing(cx, span, ident, summary, |sp| rand_call(sp)))
}
}
}.collect::<~[ast::Arm]>();
@@ -130,20 +128,20 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
fn rand_thing(cx: @ExtCtxt, span: Span,
ctor_ident: Ident,
summary: &Either<uint, ~[Ident]>,
rand_call: &fn() -> @Expr) -> @Expr {
summary: &StaticFields,
rand_call: &fn(Span) -> @Expr) -> @Expr {
match *summary {
Left(count) => {
if count == 0 {
Unnamed(ref fields) => {
if fields.is_empty() {
cx.expr_ident(span, ctor_ident)
} else {
let exprs = vec::from_fn(count, |_| rand_call());
let exprs = fields.map(|span| rand_call(*span));
cx.expr_call_ident(span, ctor_ident, exprs)
}
}
Right(ref fields) => {
let rand_fields = do fields.map |ident| {
cx.field_imm(span, *ident, rand_call())
Named(ref fields) => {
let rand_fields = do fields.map |&(ident, span)| {
cx.field_imm(span, ident, rand_call(span))
};
cx.expr_struct_ident(span, ctor_ident, rand_fields)
}
+4 -4
View File
@@ -49,7 +49,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
let to_str = cx.ident_of("to_str");
let doit = |start: &str, end: @str, name: ast::Ident,
fields: &[(Option<ast::Ident>, @Expr, ~[@Expr])]| {
fields: &[FieldInfo]| {
if fields.len() == 0 {
cx.expr_str_uniq(span, cx.str_of(name))
} else {
@@ -65,7 +65,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
stmts.push(cx.stmt_expr(call));
};
for (i, &(name, e, _)) in fields.iter().enumerate() {
for (i, &FieldInfo {name, span, self_, _}) in fields.iter().enumerate() {
if i > 0 {
push(cx.expr_str(span, @", "));
}
@@ -76,7 +76,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
push(cx.expr_str(span, name.to_managed()));
}
}
push(cx.expr_method_call(span, e, to_str, ~[]));
push(cx.expr_method_call(span, self_, to_str, ~[]));
}
push(cx.expr_str(span, end));
@@ -86,7 +86,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
return match *substr.fields {
Struct(ref fields) => {
if fields.len() == 0 || fields[0].n0_ref().is_none() {
if fields.len() == 0 || fields[0].name.is_none() {
doit("(", @")", substr.type_ident, *fields)
} else {
doit("{", @"}", substr.type_ident, *fields)
+7 -9
View File
@@ -14,8 +14,6 @@
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use std::vec;
pub fn expand_deriving_zero(cx: @ExtCtxt,
span: Span,
mitem: @MetaItem,
@@ -62,22 +60,22 @@ fn zero_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
cx.ident_of("Zero"),
cx.ident_of("zero")
];
let zero_call = cx.expr_call_global(span, zero_ident.clone(), ~[]);
let zero_call = |span| cx.expr_call_global(span, zero_ident.clone(), ~[]);
return match *substr.fields {
StaticStruct(_, ref summary) => {
match *summary {
Left(count) => {
if count == 0 {
Unnamed(ref fields) => {
if fields.is_empty() {
cx.expr_ident(span, substr.type_ident)
} else {
let exprs = vec::from_elem(count, zero_call);
let exprs = fields.map(|sp| zero_call(*sp));
cx.expr_call_ident(span, substr.type_ident, exprs)
}
}
Right(ref fields) => {
let zero_fields = do fields.map |ident| {
cx.field_imm(span, *ident, zero_call)
Named(ref fields) => {
let zero_fields = do fields.map |&(ident, span)| {
cx.field_imm(span, ident, zero_call(span))
};
cx.expr_struct_ident(span, substr.type_ident, zero_fields)
}
@@ -0,0 +1,23 @@
// 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.
#[feature(struct_variant)];
struct NotEq;
#[deriving(Eq)]
enum Foo {
Bar {
x: NotEq //~ ERROR mismatched types
//~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
}
}
pub fn main() {}
@@ -0,0 +1,22 @@
// 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.
#[feature(struct_variant)];
struct NotEq;
#[deriving(Eq)]
enum Foo {
Bar(NotEq), //~ ERROR mismatched types
//~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
Baz { x: NotEq }
}
pub fn main() {}
@@ -0,0 +1,19 @@
// 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.
struct NotEq;
#[deriving(Eq)]
struct Foo {
x: NotEq //~ ERROR mismatched types
//~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
}
pub fn main() {}
@@ -0,0 +1,19 @@
// 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.
struct NotEq;
#[deriving(Eq)]
struct Foo (
NotEq //~ ERROR mismatched types
//~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
);
pub fn main() {}