mirror of
https://github.com/rust-lang/rust.git
synced 2026-06-01 14:10:03 +03:00
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:
@@ -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() {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {}
|
||||
Reference in New Issue
Block a user