From 812ea9e169d6edcc138e334e7e2b2cb5f7ba66b3 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 7 Nov 2013 18:49:01 +1100 Subject: [PATCH] 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. --- src/libsyntax/ext/deriving/clone.rs | 10 +- src/libsyntax/ext/deriving/decodable.rs | 81 ++- src/libsyntax/ext/deriving/default.rs | 16 +- src/libsyntax/ext/deriving/encodable.rs | 11 +- src/libsyntax/ext/deriving/generic.rs | 471 ++++++++++-------- src/libsyntax/ext/deriving/iter_bytes.rs | 4 +- src/libsyntax/ext/deriving/rand.rs | 22 +- src/libsyntax/ext/deriving/to_str.rs | 8 +- src/libsyntax/ext/deriving/zero.rs | 16 +- ...deriving-field-span-enum-struct-variant.rs | 23 + .../compile-fail/deriving-field-span-enum.rs | 22 + .../deriving-field-span-struct.rs | 19 + .../deriving-field-span-tuple-struct.rs | 19 + 13 files changed, 410 insertions(+), 312 deletions(-) create mode 100644 src/test/compile-fail/deriving-field-span-enum-struct-variant.rs create mode 100644 src/test/compile-fail/deriving-field-span-enum.rs create mode 100644 src/test/compile-fail/deriving-field-span-struct.rs create mode 100644 src/test/compile-fail/deriving-field-span-tuple-struct.rs diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 5b107a49175ad..6ff39351448ba 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -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() { diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 91fe71c54145e..4ad835f032f84 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -13,9 +13,7 @@ The compiler code necessary for #[deriving(Decodable)]. See 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) + } + } +} diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs index d8c78842808d3..6bc2b06806b85 100644 --- a/src/libsyntax/ext/deriving/default.rs +++ b/src/libsyntax/ext/deriving/default.rs @@ -14,8 +14,6 @@ use ext::base::ExtCtxt; 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) } diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index d1c436c045d2b..a037a4daabfeb 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -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, diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 82a779546fcea..cfb6048df18f1 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -59,7 +59,7 @@ associated with. It is only not `None` when the associated field has 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`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 @@ impl Eq for int { *self == *other } } - ``` +~~~ Some examples of the values of `SubstructureFields` follow, using the above `Eq`, `A`, `B` and `C`. @@ -100,50 +100,62 @@ above `Eq`, `A`, `B` and `C`. When generating the `expr` for the `A` impl, the `SubstructureFields` is - ``` -Struct(~[(Some(), - , - ~[ + name: Some(), + self_: , + other: ~[, + name: None, - ~[])]) - ``` + ~[] + }]) +~~~ ## Enums When generating the `expr` for a call with `self == C0(a)` and `other == C0(b)`, the SubstructureFields is - ``` +~~~ EnumMatching(0, , - ~[None, - , - ~[]]) - ``` + ~[FieldInfo { + span: + name: None, + self_: , + other: ~[] + }]) +~~~ For `C1 {x}` and `C1 {x}`, - ``` +~~~ EnumMatching(1, , - ~[Some(), - , - ~[]]) - ``` + ~[FieldInfo { + span: + name: Some(), + self_: , + other: ~[] + }]) +~~~ For `C0(a)` and `C1 {x}` , - ``` +~~~ EnumNonMatching(~[(0, , - ~[(None, )]), + ~[(, None, )]), (1, , - ~[(Some(), + ~[(, Some(), )])]) - ``` +~~~ (and vice versa, but with the order of the outermost list flipped.) @@ -152,13 +164,13 @@ EnumNonMatching(~[(0, , A static method on the above would result in, ~~~~ -StaticStruct(, Right(~[])) +StaticStruct(, Named(~[(, )])) -StaticStruct(, Left(1)) +StaticStruct(, Unnamed(~[])) -StaticEnum(, ~[(, Left(1)), - (, Right(~[]))]) - ``` +StaticEnum(, ~[(, Unnamed(~[])), + (, Named(~[(, )]))]) +~~~ */ @@ -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, + /// 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, @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, @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, @Expr)])]), + EnumNonMatching(&'self [(uint, ast::variant, ~[(Span, Option, @Expr)])]), - /// A static method where Self is a struct - StaticStruct(&'self ast::struct_def, Either), - /// A static method where Self is an enum - StaticEnum(&'self ast::enum_def, ~[(Ident, Either)]) + /// 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 @@ representing each variant: (variant index, ast::variant instance, pub type EnumNonMatchFunc<'self> = &'self fn(@ExtCtxt, Span, &[(uint, ast::variant, - ~[(Option, @Expr)])], + ~[(Span, Option, @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 @@ impl<'self> TraitDef<'self> { 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 @@ impl<'self> TraitDef<'self> { * 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 @@ impl<'self> TraitDef<'self> { 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 @@ impl<'self> TraitDef<'self> { // 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 @@ impl<'self> TraitDef<'self> { }; // 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 @@ impl<'self> TraitDef<'self> { } 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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'self> { 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 @@ impl<'self> MethodDef<'self> { 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 @@ impl<'self> MethodDef<'self> { (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 @@ impl<'self> MethodDef<'self> { 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 @@ impl<'self> MethodDef<'self> { } } } - ``` + ~~~ */ 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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'self> { } } } - ``` + ~~~ */ 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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'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, matches_so_far: &mut ~[(uint, ast::variant, - ~[(Option, @Expr)])], + ~[(Span, Option, @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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'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 @@ impl<'self> MethodDef<'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 { +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, @Expr)]) { + trait_span: Span, + struct_ident: Ident, + struct_def: &struct_def, + prefix: &str, + mutbl: ast::Mutability) + -> (@ast::Pat, ~[(Span, Option, @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, @Expr)]) { + variant: &ast::variant, + prefix: &str, + mutbl: ast::Mutability) + -> (@ast::Pat, ~[(Span, Option, @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 @@ on all the fields. #[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 diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs index 0f4e57b0889ab..82f449fc11673 100644 --- a/src/libsyntax/ext/deriving/iter_bytes.rs +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -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 { diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 56f92246d8fe0..1e2a6fa2eb51b 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -15,8 +15,6 @@ use ext::base::ExtCtxt; 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, - 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) } diff --git a/src/libsyntax/ext/deriving/to_str.rs b/src/libsyntax/ext/deriving/to_str.rs index 77dbafa5ad7b0..69e5ce566f4cf 100644 --- a/src/libsyntax/ext/deriving/to_str.rs +++ b/src/libsyntax/ext/deriving/to_str.rs @@ -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, @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) diff --git a/src/libsyntax/ext/deriving/zero.rs b/src/libsyntax/ext/deriving/zero.rs index 2546cfc2e3999..827491ad8cb0e 100644 --- a/src/libsyntax/ext/deriving/zero.rs +++ b/src/libsyntax/ext/deriving/zero.rs @@ -14,8 +14,6 @@ use ext::base::ExtCtxt; 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) } diff --git a/src/test/compile-fail/deriving-field-span-enum-struct-variant.rs b/src/test/compile-fail/deriving-field-span-enum-struct-variant.rs new file mode 100644 index 0000000000000..44b56e09840ac --- /dev/null +++ b/src/test/compile-fail/deriving-field-span-enum-struct-variant.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/compile-fail/deriving-field-span-enum.rs b/src/test/compile-fail/deriving-field-span-enum.rs new file mode 100644 index 0000000000000..8189744de1e72 --- /dev/null +++ b/src/test/compile-fail/deriving-field-span-enum.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/compile-fail/deriving-field-span-struct.rs b/src/test/compile-fail/deriving-field-span-struct.rs new file mode 100644 index 0000000000000..1add2cd689431 --- /dev/null +++ b/src/test/compile-fail/deriving-field-span-struct.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/compile-fail/deriving-field-span-tuple-struct.rs b/src/test/compile-fail/deriving-field-span-tuple-struct.rs new file mode 100644 index 0000000000000..1f56e774f6277 --- /dev/null +++ b/src/test/compile-fail/deriving-field-span-tuple-struct.rs @@ -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 or the MIT license +// , 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() {}