From e9bf0ac9a1bdc84399644292dfb0c1844432d367 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 7 Sep 2014 12:39:47 -0700 Subject: [PATCH 1/7] syntax: Minor whitespace cleanup --- src/libsyntax/ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 68a1c521f1942..59895dbdc9c75 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -925,7 +925,7 @@ pub enum Ty_ { TyProc(Gc), TyBareFn(Gc), TyUnboxedFn(Gc), - TyTup(Vec> ), + TyTup(Vec>), TyPath(Path, Option, NodeId), // for #7264; see above /// No-op; kept solely so that we can pretty-print faithfully TyParen(P), From 2d38f5dde9a77bde533b3b4931dc6533866b8e2a Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 7 Sep 2014 13:04:33 -0700 Subject: [PATCH 2/7] syntax: minor cleanup of #[deriving(Clone)] --- src/libsyntax/ext/deriving/clone.rs | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index bbe96018f4b3d..d67fb6da4cd3f 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -40,7 +40,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, ret_ty: Self, attributes: attrs, combine_substructure: combine_substructure(|c, s, sub| { - cs_clone("Clone", c, s, sub) + cs_clone(c, s, sub) }), } ) @@ -50,14 +50,15 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, } fn cs_clone( - name: &str, - cx: &mut ExtCtxt, trait_span: Span, + cx: &mut ExtCtxt, + trait_span: Span, substr: &Substructure) -> Gc { let clone_ident = substr.method_ident; let ctor_ident; let all_fields; - let subcall = |field: &FieldInfo| - cx.expr_method_call(field.span, field.self_, clone_ident, Vec::new()); + let subcall = |field: &FieldInfo| { + cx.expr_method_call(field.span, field.self_, clone_ident, Vec::new()) + }; match *substr.fields { Struct(ref af) => { @@ -68,16 +69,11 @@ fn cs_clone( ctor_ident = variant.node.name; all_fields = af; }, - EnumNonMatchingCollapsed (..) => { - cx.span_bug(trait_span, - format!("non-matching enum variants in \ - `deriving({})`", - name).as_slice()) + EnumNonMatchingCollapsed(..) => { + cx.span_bug(trait_span, "non-matching enum variants in `#[deriving(Clone)]`") } StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, - format!("static method in `deriving({})`", - name).as_slice()) + cx.span_bug(trait_span, "static method in `#[deriving(Clone)]`") } } @@ -91,10 +87,8 @@ fn cs_clone( let ident = match field.name { Some(i) => i, None => { - cx.span_bug(trait_span, - format!("unnamed field in normal struct in \ - `deriving({})`", - name).as_slice()) + cx.span_bug(trait_span, "unnamed field in normal struct in \ + `#[deriving(Clone)]`") } }; cx.field_imm(field.span, ident, subcall(field)) From 45c5baeac35cb1911855c8b9b65eceee40a967d6 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 7 Sep 2014 13:04:44 -0700 Subject: [PATCH 3/7] remove executable bit from a test --- src/test/auxiliary/lint_output_format.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/test/auxiliary/lint_output_format.rs diff --git a/src/test/auxiliary/lint_output_format.rs b/src/test/auxiliary/lint_output_format.rs old mode 100755 new mode 100644 From 7df71b09592d8dfbcc64a86ad80714a667a41829 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 7 Sep 2014 11:40:12 -0700 Subject: [PATCH 4/7] syntax: Substructure.fields doesn't need to be a reference --- src/libsyntax/ext/deriving/clone.rs | 2 +- src/libsyntax/ext/deriving/decodable.rs | 4 +- src/libsyntax/ext/deriving/default.rs | 4 +- src/libsyntax/ext/deriving/encodable.rs | 4 +- src/libsyntax/ext/deriving/generic/mod.rs | 19 +++++----- src/libsyntax/ext/deriving/hash.rs | 2 +- src/libsyntax/ext/deriving/primitive.rs | 2 +- src/libsyntax/ext/deriving/rand.rs | 46 +++++++++++------------ src/libsyntax/ext/deriving/show.rs | 4 +- src/libsyntax/ext/deriving/zero.rs | 4 +- 10 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index d67fb6da4cd3f..947a5d257dab5 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -60,7 +60,7 @@ fn cs_clone( cx.expr_method_call(field.span, field.self_, clone_ident, Vec::new()) }; - match *substr.fields { + match substr.fields { Struct(ref af) => { ctor_ident = substr.type_ident; all_fields = af; diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index d909ffd2b49fb..33ed769fb3029 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -75,7 +75,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, let calldecode = cx.expr_call_global(trait_span, recurse, vec!(blkdecoder)); let lambdadecode = cx.lambda_expr_1(trait_span, calldecode, blkarg); - return match *substr.fields { + match substr.fields { StaticStruct(_, ref summary) => { let nfields = match *summary { Unnamed(ref fields) => fields.len(), @@ -149,7 +149,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, )) } _ => cx.bug("expected StaticEnum or StaticStruct in deriving(Decodable)") - }; + } } /// Create a decoder for a single enum variant/struct: diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs index f7d0308e1bd21..7656071260dbb 100644 --- a/src/libsyntax/ext/deriving/default.rs +++ b/src/libsyntax/ext/deriving/default.rs @@ -57,7 +57,7 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, ); let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new()); - return match *substr.fields { + match substr.fields { StaticStruct(_, ref summary) => { match *summary { Unnamed(ref fields) => { @@ -82,5 +82,5 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, cx.expr_uint(trait_span, 0) } _ => cx.span_bug(trait_span, "Non-static method in `deriving(Default)`") - }; + } } diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 02a748eed8e47..826681ad08790 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -138,7 +138,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, let blkencoder = cx.expr_ident(trait_span, blkarg); let encode = cx.ident_of("encode"); - return match *substr.fields { + match substr.fields { Struct(ref fields) => { let emit_struct_field = cx.ident_of("emit_struct_field"); let mut stmts = Vec::new(); @@ -245,5 +245,5 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, } _ => cx.bug("expected Struct or EnumMatching in deriving(Encodable)") - }; + } } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 50bdc296aad76..a86428ec64b7b 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -254,7 +254,8 @@ pub struct Substructure<'a> { pub self_args: &'a [Gc], /// verbatim access to any other arguments pub nonself_args: &'a [Gc], - pub fields: &'a SubstructureFields<'a> + /// The data structure fields + pub fields: SubstructureFields<'a> } /// Summary of the relevant parts of a struct/enum field. @@ -568,7 +569,7 @@ impl<'a> MethodDef<'a> { type_ident: Ident, self_args: &[Gc], nonself_args: &[Gc], - fields: &SubstructureFields) + fields: SubstructureFields) -> Gc { let substructure = Substructure { type_ident: type_ident, @@ -769,7 +770,7 @@ impl<'a> MethodDef<'a> { type_ident, self_args, nonself_args, - &Struct(fields)); + Struct(fields)); // make a series of nested matches, to destructure the // structs. This is actually right-to-left, but it shouldn't @@ -795,7 +796,7 @@ impl<'a> MethodDef<'a> { trait_, type_ident, self_args, nonself_args, - &StaticStruct(struct_def, summary)) + StaticStruct(struct_def, summary)) } /** @@ -991,7 +992,7 @@ impl<'a> MethodDef<'a> { field_tuples); let arm_expr = self.call_substructure_method( cx, trait_, type_ident, self_args, nonself_args, - &substructure); + substructure); cx.arm(sp, vec![single_pat], arm_expr) }).collect(); @@ -1044,7 +1045,7 @@ impl<'a> MethodDef<'a> { let arm_expr = self.call_substructure_method( cx, trait_, type_ident, self_args, nonself_args, - &catch_all_substructure); + catch_all_substructure); // Builds the expression: // { @@ -1153,7 +1154,7 @@ impl<'a> MethodDef<'a> { }).collect(); self.call_substructure_method(cx, trait_, type_ident, self_args, nonself_args, - &StaticEnum(enum_def, summary)) + StaticEnum(enum_def, summary)) } } @@ -1334,7 +1335,7 @@ pub fn cs_fold(use_foldl: bool, trait_span: Span, substructure: &Substructure) -> Gc { - match *substructure.fields { + match substructure.fields { EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { if use_foldl { all_fields.iter().fold(base, |old, field| { @@ -1380,7 +1381,7 @@ pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec>| -> Gc, trait_span: Span, substructure: &Substructure) -> Gc { - match *substructure.fields { + match substructure.fields { EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { // call self_n.method(other_1_n, other_2_n, ...) let called = all_fields.iter().map(|field| { diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index f469139177a0b..8a1ca0583ba74 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -77,7 +77,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, }; let mut stmts = Vec::new(); - let fields = match *substr.fields { + let fields = match substr.fields { Struct(ref fs) => fs, EnumMatching(index, variant, ref fs) => { // Determine the discriminant. We will feed this value to the byte diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index 30dd8e9683ad5..5494b7e6704bc 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -77,7 +77,7 @@ fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, _ => cx.span_bug(trait_span, "incorrect number of arguments in `deriving(FromPrimitive)`") }; - match *substr.fields { + match substr.fields { StaticStruct(..) => { cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs"); return cx.expr_fail(trait_span, InternedString::new("")); diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index c652b5a5bed9a..31f00af3b3e87 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -72,7 +72,7 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, vec!( *rng.get(0) )) }; - return match *substr.fields { + match substr.fields { StaticStruct(_, ref summary) => { rand_thing(cx, trait_span, substr.type_ident, summary, rand_call) } @@ -130,30 +130,30 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, cx.expr_block(block) } _ => cx.bug("Non-static method in `deriving(Rand)`") - }; + } +} - fn rand_thing(cx: &mut ExtCtxt, - trait_span: Span, - ctor_ident: Ident, - summary: &StaticFields, - rand_call: |&mut ExtCtxt, Span| -> Gc) - -> Gc { - match *summary { - Unnamed(ref fields) => { - if fields.is_empty() { - cx.expr_ident(trait_span, ctor_ident) - } else { - let exprs = fields.iter().map(|span| rand_call(cx, *span)).collect(); - cx.expr_call_ident(trait_span, ctor_ident, exprs) - } - } - Named(ref fields) => { - let rand_fields = fields.iter().map(|&(ident, span)| { - let e = rand_call(cx, span); - cx.field_imm(span, ident, e) - }).collect(); - cx.expr_struct_ident(trait_span, ctor_ident, rand_fields) +fn rand_thing(cx: &mut ExtCtxt, + trait_span: Span, + ctor_ident: Ident, + summary: &StaticFields, + rand_call: |&mut ExtCtxt, Span| -> Gc) + -> Gc { + match *summary { + Unnamed(ref fields) => { + if fields.is_empty() { + cx.expr_ident(trait_span, ctor_ident) + } else { + let exprs = fields.iter().map(|span| rand_call(cx, *span)).collect(); + cx.expr_call_ident(trait_span, ctor_ident, exprs) } } + Named(ref fields) => { + let rand_fields = fields.iter().map(|&(ident, span)| { + let e = rand_call(cx, span); + cx.field_imm(span, ident, e) + }).collect(); + cx.expr_struct_ident(trait_span, ctor_ident, rand_fields) + } } } diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs index e0dfbb232f554..b586d6f5b68a1 100644 --- a/src/libsyntax/ext/deriving/show.rs +++ b/src/libsyntax/ext/deriving/show.rs @@ -62,7 +62,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, // : {}, ... }` based on the "shape". // // Easy start: they all start with the name. - let name = match *substr.fields { + let name = match substr.fields { Struct(_) => substr.type_ident, EnumMatching(_, v, _) => v.node.name, EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { @@ -75,7 +75,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, let mut exprs = Vec::new(); // Getting harder... making the format string: - match *substr.fields { + match substr.fields { // unit struct/nullary variant: no work necessary! Struct(ref fields) if fields.len() == 0 => {} EnumMatching(_, _, ref fields) if fields.len() == 0 => {} diff --git a/src/libsyntax/ext/deriving/zero.rs b/src/libsyntax/ext/deriving/zero.rs index 973f9d518cd70..9a083a1275ad5 100644 --- a/src/libsyntax/ext/deriving/zero.rs +++ b/src/libsyntax/ext/deriving/zero.rs @@ -73,7 +73,7 @@ fn zero_substructure(cx: &mut ExtCtxt, trait_span: Span, ); let zero_call = |span| cx.expr_call_global(span, zero_ident.clone(), Vec::new()); - return match *substr.fields { + match substr.fields { StaticStruct(_, ref summary) => { match *summary { Unnamed(ref fields) => { @@ -98,5 +98,5 @@ fn zero_substructure(cx: &mut ExtCtxt, trait_span: Span, cx.expr_uint(trait_span, 0) } _ => cx.bug("Non-static method in `deriving(Zero)`") - }; + } } From fae4c2bdb726548aadd73749e413811189425fa0 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 7 Sep 2014 11:46:46 -0700 Subject: [PATCH 5/7] syntax: add attributes to FieldInfo --- src/libsyntax/ext/deriving/generic/mod.rs | 162 +++++++++++----------- 1 file changed, 83 insertions(+), 79 deletions(-) diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index a86428ec64b7b..413a06103bab0 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -259,7 +259,7 @@ pub struct Substructure<'a> { } /// Summary of the relevant parts of a struct/enum field. -pub struct FieldInfo { +pub struct FieldInfo<'a> { pub span: Span, /// None for tuple structs/normal enum variants, Some for normal /// structs/struct enum variants. @@ -270,6 +270,8 @@ pub struct FieldInfo { /// The expressions corresponding to references to this field in /// the other Self arguments. pub other: Vec>, + /// The attributes attached to this field. + pub attrs: &'a [ast::Attribute], } /// Fields for a static method @@ -283,13 +285,13 @@ pub enum StaticFields { /// A summary of the possible sets of fields. See above for details /// and examples pub enum SubstructureFields<'a> { - Struct(Vec), + Struct(Vec>), /** Matching variants of the enum: variant index, ast::Variant, fields: the field name is only non-`None` in the case of a struct variant. */ - EnumMatching(uint, &'a ast::Variant, Vec), + EnumMatching(uint, &'a ast::Variant, Vec>), /** non-matching variants of the enum, but with all state hidden from @@ -472,11 +474,11 @@ impl<'a> TraitDef<'a> { }).collect())) } - fn expand_struct_def(&self, - cx: &mut ExtCtxt, - struct_def: &StructDef, - type_ident: Ident, - generics: &Generics) -> Gc { + fn expand_struct_def<'b>(&self, + cx: &mut ExtCtxt, + struct_def: &'b StructDef, + type_ident: Ident, + generics: &Generics) -> Gc { let methods = self.methods.iter().map(|method_def| { let (explicit_self, self_args, nonself_args, tys) = method_def.split_self_nonself_args( @@ -512,11 +514,11 @@ impl<'a> TraitDef<'a> { self.create_derived_impl(cx, type_ident, generics, methods) } - fn expand_enum_def(&self, - cx: &mut ExtCtxt, - enum_def: &EnumDef, - type_ident: Ident, - generics: &Generics) -> Gc { + fn expand_enum_def<'b>(&self, + cx: &mut ExtCtxt, + enum_def: &'b EnumDef, + type_ident: Ident, + generics: &Generics) -> Gc { let methods = self.methods.iter().map(|method_def| { let (explicit_self, self_args, nonself_args, tys) = method_def.split_self_nonself_args(cx, self, @@ -563,13 +565,13 @@ fn variant_to_pat(cx: &mut ExtCtxt, sp: Span, variant: &ast::Variant) } impl<'a> MethodDef<'a> { - fn call_substructure_method(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - self_args: &[Gc], - nonself_args: &[Gc], - fields: SubstructureFields) + fn call_substructure_method<'b>(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + type_ident: Ident, + self_args: &'b [Gc], + nonself_args: &'b [Gc], + fields: SubstructureFields<'b>) -> Gc { let substructure = Substructure { type_ident: type_ident, @@ -715,13 +717,13 @@ impl<'a> MethodDef<'a> { } ~~~ */ - fn expand_struct_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - struct_def: &StructDef, - type_ident: Ident, - self_args: &[Gc], - nonself_args: &[Gc]) + fn expand_struct_method_body<'b>(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + struct_def: &'b StructDef, + type_ident: Ident, + self_args: &'b [Gc], + nonself_args: &'b [Gc]) -> Gc { let mut raw_fields = Vec::new(); // ~[[fields of self], @@ -744,17 +746,18 @@ impl<'a> MethodDef<'a> { raw_fields.get(0) .iter() .enumerate() - .map(|(i, &(span, opt_id, field))| { + .map(|(i, &(span, opt_id, field, attrs))| { let other_fields = raw_fields.tail().iter().map(|l| { match l.get(i) { - &(_, _, ex) => ex + &(_, _, ex, _) => ex } }).collect(); FieldInfo { span: span, name: opt_id, self_: field, - other: other_fields + other: other_fields, + attrs: attrs, } }).collect() } else { @@ -782,13 +785,13 @@ impl<'a> MethodDef<'a> { body } - fn expand_static_struct_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - struct_def: &StructDef, - type_ident: Ident, - self_args: &[Gc], - nonself_args: &[Gc]) + fn expand_static_struct_method_body<'b>(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + struct_def: &'b StructDef, + type_ident: Ident, + self_args: &[Gc], + nonself_args: &[Gc]) -> Gc { let summary = trait_.summarise_struct(cx, struct_def); @@ -830,14 +833,14 @@ impl<'a> MethodDef<'a> { as their results are unused. The point of `__self_vi` and `__arg_1_vi` is for `PartialOrd`; see #15503.) */ - fn expand_enum_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, - type_ident: Ident, - self_args: &[Gc], - nonself_args: &[Gc]) - -> Gc { + fn expand_enum_method_body<'b>(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + enum_def: &'b EnumDef, + type_ident: Ident, + self_args: &[Gc], + nonself_args: &[Gc]) + -> Gc { self.build_enum_match_tuple( cx, trait_, enum_def, type_ident, self_args, nonself_args) } @@ -870,14 +873,14 @@ impl<'a> MethodDef<'a> { } ~~~ */ - fn build_enum_match_tuple( - &self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, - type_ident: Ident, - self_args: &[Gc], - nonself_args: &[Gc]) -> Gc { + fn build_enum_match_tuple<'b>(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + enum_def: &'b EnumDef, + type_ident: Ident, + self_args: &[Gc], + nonself_args: &[Gc]) + -> Gc { let sp = trait_.span; let variants = &enum_def.variants; @@ -920,7 +923,7 @@ impl<'a> MethodDef<'a> { // These self_pats have form Variant1, Variant2, ... let self_pats : Vec<(Gc, - Vec<(Span, Option, Gc)>)>; + Vec<(Span, Option, Gc, &[ast::Attribute])>)>; self_pats = self_arg_names.iter() .map(|self_arg_name| trait_.create_enum_variant_pattern( @@ -954,7 +957,7 @@ impl<'a> MethodDef<'a> { field_tuples = self_arg_fields.iter().enumerate() // For each arg field of self, pull out its getter expr ... - .map(|(field_index, &(sp, opt_ident, self_getter_expr))| { + .map(|(field_index, &(sp, opt_ident, self_getter_expr, attrs))| { // ... but FieldInfo also wants getter expr // for matching other arguments of Self type; // so walk across the *other* self_pats and @@ -964,7 +967,7 @@ impl<'a> MethodDef<'a> { let others = self_pats.tail().iter() .map(|&(_pat, ref fields)| { - let &(_, _opt_ident, other_getter_expr) = + let &(_, _opt_ident, other_getter_expr, _) = fields.get(field_index); // All Self args have same variant, so @@ -980,6 +983,7 @@ impl<'a> MethodDef<'a> { name: opt_ident, self_: self_getter_expr, other: others, + attrs: attrs, } }).collect::>(); @@ -1132,13 +1136,13 @@ impl<'a> MethodDef<'a> { cx.expr_match(sp, match_arg, match_arms) } - fn expand_static_enum_method_body(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - enum_def: &EnumDef, - type_ident: Ident, - self_args: &[Gc], - nonself_args: &[Gc]) + fn expand_static_enum_method_body<'b>(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + enum_def: &'b EnumDef, + type_ident: Ident, + self_args: &[Gc], + nonself_args: &[Gc]) -> Gc { let summary = enum_def.variants.iter().map(|v| { let ident = v.node.name; @@ -1218,13 +1222,13 @@ impl<'a> TraitDef<'a> { }).collect() } - fn create_struct_pattern(&self, - cx: &mut ExtCtxt, - struct_ident: Ident, - struct_def: &StructDef, - prefix: &str, - mutbl: ast::Mutability) - -> (Gc, Vec<(Span, Option, Gc)>) { + fn create_struct_pattern<'b>(&self, + cx: &mut ExtCtxt, + struct_ident: Ident, + struct_def: &'b StructDef, + prefix: &str, + mutbl: ast::Mutability) + -> (Gc, Vec<(Span, Option, Gc, &'b [ast::Attribute])>) { if struct_def.fields.is_empty() { return ( cx.pat_ident_binding_mode( @@ -1259,7 +1263,7 @@ impl<'a> TraitDef<'a> { paths.push(codemap::Spanned{span: sp, node: ident}); let val = cx.expr( sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident))))); - ident_expr.push((sp, opt_id, val)); + ident_expr.push((sp, opt_id, val, struct_field.node.attrs.as_slice())); } let subpats = self.create_subpatterns(cx, paths, mutbl); @@ -1267,7 +1271,7 @@ impl<'a> TraitDef<'a> { // 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 = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _))| { + let field_pats = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _, _))| { // id is guaranteed to be Some ast::FieldPat { ident: id.unwrap(), pat: pat } }).collect(); @@ -1279,12 +1283,12 @@ impl<'a> TraitDef<'a> { (pattern, ident_expr) } - fn create_enum_variant_pattern(&self, - cx: &mut ExtCtxt, - variant: &ast::Variant, - prefix: &str, - mutbl: ast::Mutability) - -> (Gc, Vec<(Span, Option, Gc)> ) { + fn create_enum_variant_pattern<'a>(&self, + cx: &mut ExtCtxt, + variant: &'a ast::Variant, + prefix: &str, + mutbl: ast::Mutability) + -> (Gc, Vec<(Span, Option, Gc, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; match variant.node.kind { ast::TupleVariantKind(ref variant_args) => { @@ -1305,7 +1309,7 @@ impl<'a> TraitDef<'a> { paths.push(path1); let expr_path = cx.expr_path(cx.path_ident(sp, ident)); let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path))); - ident_expr.push((sp, None, val)); + ident_expr.push((sp, None, val, variant.node.attrs.as_slice())); } let subpats = self.create_subpatterns(cx, paths, mutbl); From 3142a126b35c0c765e129342eeedddf38a1f9705 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 7 Sep 2014 12:39:34 -0700 Subject: [PATCH 6/7] syntax: allow passing struct field attributes to deriving static handlers --- src/libsyntax/ext/deriving/decodable.rs | 6 +-- src/libsyntax/ext/deriving/default.rs | 4 +- src/libsyntax/ext/deriving/generic/mod.rs | 48 ++++++++++++++++------- src/libsyntax/ext/deriving/rand.rs | 6 +-- src/libsyntax/ext/deriving/zero.rs | 4 +- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 33ed769fb3029..6ba13e962542f 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -178,9 +178,9 @@ fn decode_static_fields(cx: &mut ExtCtxt, } Named(ref fields) => { // use the field's span to get nicer error messages. - let fields = fields.iter().enumerate().map(|(i, &(name, span))| { - let arg = getarg(cx, span, token::get_ident(name), i); - cx.field_imm(span, name, arg) + let fields = fields.iter().enumerate().map(|(i, field)| { + let arg = getarg(cx, field.span, token::get_ident(field.name), i); + cx.field_imm(field.span, field.name, arg) }).collect(); cx.expr_struct_ident(trait_span, outer_pat_ident, fields) } diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs index 7656071260dbb..d2385f3420014 100644 --- a/src/libsyntax/ext/deriving/default.rs +++ b/src/libsyntax/ext/deriving/default.rs @@ -69,8 +69,8 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, } } Named(ref fields) => { - let default_fields = fields.iter().map(|&(ident, span)| { - cx.field_imm(span, ident, default_call(span)) + let default_fields = fields.iter().map(|field| { + cx.field_imm(field.span, field.name, default_call(field.span)) }).collect(); cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 413a06103bab0..21a40cab9ceb6 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -274,12 +274,20 @@ pub struct FieldInfo<'a> { pub attrs: &'a [ast::Attribute], } +pub struct StaticFieldInfo<'a> { + pub span: Span, + /// The field's ident. + pub name: Ident, + /// The attributes attached to this field. + pub attrs: &'a [ast::Attribute], +} + /// Fields for a static method -pub enum StaticFields { +pub enum StaticFields<'a> { /// Tuple structs/enum variants like this Unnamed(Vec), /// Normal structs/struct variants. - Named(Vec<(Ident, Span)>), + Named(Vec<(StaticFieldInfo<'a>)>), } /// A summary of the possible sets of fields. See above for details @@ -304,9 +312,9 @@ pub enum SubstructureFields<'a> { EnumNonMatchingCollapsed(Vec, &'a [Gc], &'a [Ident]), /// A static method where Self is a struct. - StaticStruct(&'a ast::StructDef, StaticFields), + StaticStruct(&'a ast::StructDef, StaticFields<'a>), /// A static method where Self is an enum. - StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>), + StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields<'a>)>), } @@ -1187,25 +1195,37 @@ impl<'a> TraitDef<'a> { to_set } - fn summarise_struct(&self, - cx: &mut ExtCtxt, - struct_def: &StructDef) -> StaticFields { - let mut named_idents = Vec::new(); + fn summarise_struct<'b>(&self, + cx: &mut ExtCtxt, + struct_def: &'b StructDef) -> StaticFields<'b> { + let mut named_fields = Vec::new(); let mut just_spans = Vec::new(); - for field in struct_def.fields.iter(){ - let sp = self.set_expn_info(cx, field.span); + + for field in struct_def.fields.iter() { + let span = self.set_expn_info(cx, field.span); + match field.node.kind { - ast::NamedField(ident, _) => named_idents.push((ident, sp)), - ast::UnnamedField(..) => just_spans.push(sp), + ast::NamedField(ident, _) => { + let field_info = StaticFieldInfo { + span: span, + name: ident, + attrs: field.node.attrs.as_slice(), + }; + + named_fields.push(field_info); + } + ast::UnnamedField(..) => { + just_spans.push(span); + } } } - match (just_spans.is_empty(), named_idents.is_empty()) { + match (just_spans.is_empty(), named_fields.is_empty()) { (false, false) => cx.span_bug(self.span, "a struct with named and unnamed \ fields in generic `deriving`"), // named fields - (_, false) => Named(named_idents), + (_, false) => Named(named_fields), // tuple structs (includes empty structs) (_, _) => Unnamed(just_spans) } diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 31f00af3b3e87..c70e56285f242 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -149,9 +149,9 @@ fn rand_thing(cx: &mut ExtCtxt, } } Named(ref fields) => { - let rand_fields = fields.iter().map(|&(ident, span)| { - let e = rand_call(cx, span); - cx.field_imm(span, ident, e) + let rand_fields = fields.iter().map(|field| { + let e = rand_call(cx, field.span); + cx.field_imm(field.span, field.name, e) }).collect(); cx.expr_struct_ident(trait_span, ctor_ident, rand_fields) } diff --git a/src/libsyntax/ext/deriving/zero.rs b/src/libsyntax/ext/deriving/zero.rs index 9a083a1275ad5..41d667f9288ef 100644 --- a/src/libsyntax/ext/deriving/zero.rs +++ b/src/libsyntax/ext/deriving/zero.rs @@ -85,8 +85,8 @@ fn zero_substructure(cx: &mut ExtCtxt, trait_span: Span, } } Named(ref fields) => { - let zero_fields = fields.iter().map(|&(ident, span)| { - cx.field_imm(span, ident, zero_call(span)) + let zero_fields = fields.iter().map(|field| { + cx.field_imm(field.span, field.name, zero_call(field.span)) }).collect(); cx.expr_struct_ident(trait_span, substr.type_ident, zero_fields) } From db16606d80fa15b874d593fdbfb730ed6caee01a Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 7 Sep 2014 17:32:55 -0700 Subject: [PATCH 7/7] Add a test for #[deriving(...)] working with annotations --- .../syntax-extension-with-field-names.rs | 198 ++++++++++++++++++ .../syntax-extension-field-names.rs | 39 ++++ 2 files changed, 237 insertions(+) create mode 100644 src/test/auxiliary/syntax-extension-with-field-names.rs create mode 100644 src/test/run-pass-fulldeps/syntax-extension-field-names.rs diff --git a/src/test/auxiliary/syntax-extension-with-field-names.rs b/src/test/auxiliary/syntax-extension-with-field-names.rs new file mode 100644 index 0000000000000..baeecc8396325 --- /dev/null +++ b/src/test/auxiliary/syntax-extension-with-field-names.rs @@ -0,0 +1,198 @@ +// Copyright 2014 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. + +// force-host +// no-prefer-dynamic + +#![crate_type = "dylib"] +#![feature(plugin_registrar, quote)] + +extern crate syntax; +extern crate rustc; + +use std::gc::Gc; + +use syntax::ast::{ + Expr, + Ident, + Item, + MetaItem, +}; +use syntax::ast; +use syntax::attr; +use syntax::codemap::Span; +use syntax::ext::base::{ExtCtxt, ItemDecorator}; +use syntax::ext::build::AstBuilder; +use syntax::ext::deriving::generic::{ + MethodDef, + Named, + StaticStruct, + Struct, + Substructure, + TraitDef, + Unnamed, + combine_substructure, +}; +use syntax::ext::deriving::generic::ty::{ + Borrowed, + LifetimeBounds, + Literal, + Self, + Path, + Ptr, + borrowed_explicit_self, +}; +use syntax::parse::token; + +use rustc::plugin::Registry; + +#[plugin_registrar] +pub fn registrar(reg: &mut Registry) { + reg.register_syntax_extension( + token::intern("deriving_field_names"), + ItemDecorator(expand_deriving_field_names)); +} + +fn expand_deriving_field_names(cx: &mut ExtCtxt, + sp: Span, + mitem: Gc, + item: Gc, + push: |Gc|) { + let trait_def = TraitDef { + span: sp, + attributes: vec!(), + path: Path::new_local("FieldNames"), + additional_bounds: Vec::new(), + generics: LifetimeBounds::empty(), + methods: vec!( + MethodDef { + name: "field_names", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: Vec::new(), + ret_ty: Literal( + Path::new_( + vec!("Vec"), + None, + vec!( + box Ptr( + box Literal(Path::new_local("str")), + Borrowed(Some("'static"), ast::MutImmutable))), + false)), + attributes: vec!(), + combine_substructure: combine_substructure(|a, b, c| { + field_names_substructure(a, b, c) + }), + }, + MethodDef { + name: "static_field_names", + generics: LifetimeBounds::empty(), + explicit_self: None, + args: vec!( + Literal( + Path::new_( + vec!("std", "option", "Option"), + None, + vec!(box Self), + true))), + ret_ty: Literal( + Path::new_( + vec!("Vec"), + None, + vec!( + box Ptr( + box Literal(Path::new_local("str")), + Borrowed(Some("'static"), ast::MutImmutable))), + false)), + attributes: vec!(), + combine_substructure: combine_substructure(|a, b, c| { + field_names_substructure(a, b, c) + }), + }, + ) + }; + + trait_def.expand(cx, mitem, item, push) +} + +fn field_names_substructure(cx: &ExtCtxt, + _span: Span, + substr: &Substructure) -> Gc { + + let ident_attrs: Vec<(Span, Option, &[ast::Attribute])> = match substr.fields { + Struct(ref fields) => { + fields.iter() + .map(|field_info| { + (field_info.span, field_info.name, field_info.attrs) + }) + .collect() + } + StaticStruct(_, ref summary) => { + match *summary { + Unnamed(_) => { + fail!() + } + Named(ref fields) => { + fields.iter() + .map(|field_info| { + (field_info.span, Some(field_info.name), field_info.attrs) + }) + .collect() + } + } + } + + _ => cx.bug("expected Struct in deriving_test") + }; + + let stmts: Vec> = ident_attrs.iter() + .enumerate() + .map(|(i, &(span, ident, attrs))| { + let name = find_name(attrs); + + let name = match (name, ident) { + (Some(serial), _) => serial.clone(), + (None, Some(id)) => token::get_ident(id), + (None, None) => token::intern_and_get_ident(format!("_field{}", i).as_slice()), + }; + + let name = cx.expr_str(span, name); + + quote_stmt!( + cx, + parts.push($name); + ) + }) + .collect(); + + quote_expr!(cx, { + let mut parts = Vec::new(); + $stmts + parts + }) +} + +fn find_name(attrs: &[ast::Attribute]) -> Option { + for attr in attrs.iter() { + match attr.node.value.node { + ast::MetaNameValue(ref at_name, ref value) => { + match (at_name.get(), &value.node) { + ("name", &ast::LitStr(ref string, _)) => { + attr::mark_used(attr); + return Some(string.clone()); + }, + _ => () + } + }, + _ => () + } + } + None +} diff --git a/src/test/run-pass-fulldeps/syntax-extension-field-names.rs b/src/test/run-pass-fulldeps/syntax-extension-field-names.rs new file mode 100644 index 0000000000000..f08b8a0745eb3 --- /dev/null +++ b/src/test/run-pass-fulldeps/syntax-extension-field-names.rs @@ -0,0 +1,39 @@ +// Copyright 2014 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. + +// aux-build:syntax-extension-with-field-names.rs +// ignore-stage1 + +#![feature(phase)] + +#[phase(plugin)] +extern crate "syntax-extension-with-field-names" as extension; + +trait FieldNames { + fn field_names(&self) -> Vec<&'static str>; + fn static_field_names(_: Option) -> Vec<&'static str>; +} + +#[deriving_field_names] +struct Foo { + x: int, + #[name = "$y"] + y: int, +} + +fn main() { + let foo = Foo { + x: 1, + y: 2, + }; + + assert_eq!(foo.field_names(), vec!("x", "$y")); + assert_eq!(FieldNames::static_field_names(None::), vec!("x", "$y")); +}