about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ext/pipes/pipec.rs4
-rw-r--r--src/libsyntax/fold.rs73
-rw-r--r--src/libsyntax/parse/parser.rs122
-rw-r--r--src/test/run-pass/common-fields-trivial.rs14
5 files changed, 129 insertions, 86 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index c33b3e9b6ec..8f4eb98fa7b 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -641,7 +641,7 @@ enum variant_kind {
 }
 
 #[auto_serialize]
-enum enum_def = { variants: ~[variant] };
+enum enum_def = { variants: ~[variant], common: option<@struct_def> };
 
 #[auto_serialize]
 type variant_ = {name: ident, attrs: ~[attribute], kind: variant_kind,
diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs
index a835cbb27a4..f1f8eb4f452 100644
--- a/src/libsyntax/ext/pipes/pipec.rs
+++ b/src/libsyntax/ext/pipes/pipec.rs
@@ -231,7 +231,9 @@ impl state: to_type_decls {
             vec::push(items_msg, v);
         }
 
-        ~[cx.item_enum_poly(name, ast::enum_def({ variants: items_msg }),
+        ~[cx.item_enum_poly(name,
+                            ast::enum_def({ variants: items_msg,
+                                            common: none }),
                             self.ty_params)]
     }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 48d0bf12845..5cce86fd458 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -242,40 +242,13 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
             item_enum(ast::enum_def({
                 variants: vec::map(enum_definition.variants,
                                    |x| fld.fold_variant(x)),
+                common: option::map(enum_definition.common,
+                                    |x| fold_struct_def(x, fld))
             }), fold_ty_params(typms, fld))
           }
           item_class(struct_def, typms) => {
-            let resulting_optional_constructor;
-            match struct_def.ctor {
-                none => {
-                    resulting_optional_constructor = none;
-                }
-                some(constructor) => {
-                    resulting_optional_constructor = some({
-                        node: {
-                            body: fld.fold_block(constructor.node.body),
-                            dec: fold_fn_decl(constructor.node.dec, fld),
-                            id: fld.new_id(constructor.node.id)
-                            with constructor.node
-                        }
-                        with constructor
-                    });
-                }
-            }
-            let dtor = do option::map(struct_def.dtor) |dtor| {
-                let dtor_body = fld.fold_block(dtor.node.body);
-                let dtor_id   = fld.new_id(dtor.node.id);
-                {node: {body: dtor_body,
-                        id: dtor_id with dtor.node}
-                    with dtor}};
-              item_class(@{
-                  traits: vec::map(struct_def.traits,
-                                   |p| fold_trait_ref(p, fld)),
-                  members: vec::map(struct_def.members,
-                                    |x| fld.fold_class_item(x)),
-                  ctor: resulting_optional_constructor,
-                  dtor: dtor},
-                  /* FIXME (#2543) */ copy typms)
+            let struct_def = fold_struct_def(struct_def, fld);
+              item_class(struct_def, /* FIXME (#2543) */ copy typms)
           }
           item_impl(tps, ifce, ty, methods) => {
               item_impl(fold_ty_params(tps, fld),
@@ -295,6 +268,39 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
         };
 }
 
+fn fold_struct_def(struct_def: @ast::struct_def, fld: ast_fold)
+                -> @ast::struct_def {
+    let resulting_optional_constructor;
+    match struct_def.ctor {
+        none => {
+            resulting_optional_constructor = none;
+        }
+        some(constructor) => {
+            resulting_optional_constructor = some({
+                node: {
+                    body: fld.fold_block(constructor.node.body),
+                    dec: fold_fn_decl(constructor.node.dec, fld),
+                    id: fld.new_id(constructor.node.id)
+                    with constructor.node
+                }
+                with constructor
+            });
+        }
+    }
+    let dtor = do option::map(struct_def.dtor) |dtor| {
+        let dtor_body = fld.fold_block(dtor.node.body);
+        let dtor_id   = fld.new_id(dtor.node.id);
+        {node: {body: dtor_body,
+                id: dtor_id with dtor.node}
+            with dtor}};
+    return @{
+        traits: vec::map(struct_def.traits, |p| fold_trait_ref(p, fld)),
+        members: vec::map(struct_def.members, |x| fld.fold_class_item(x)),
+        ctor: resulting_optional_constructor,
+        dtor: dtor
+    };
+}
+
 fn fold_trait_ref(&&p: @trait_ref, fld: ast_fold) -> @trait_ref {
     @{path: fld.fold_path(p.path), ref_id: fld.new_id(p.ref_id),
      impl_id: fld.new_id(p.impl_id)}
@@ -570,7 +576,10 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
         enum_variant_kind(enum_definition) => {
             let variants = vec::map(enum_definition.variants,
                                     |x| fld.fold_variant(x));
-            kind = enum_variant_kind(ast::enum_def({ variants: variants }));
+            let common = option::map(enum_definition.common,
+                                     |x| fold_struct_def(x, fld));
+            kind = enum_variant_kind(ast::enum_def({ variants: variants,
+                                                     common: common }));
         }
     }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 5141c842335..28768765192 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -46,9 +46,9 @@ import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
              proto_block, proto_box, proto_uniq, provided, public, pure_fn,
              purity, re_anon, re_named, region, rem, required, ret_style,
              return_val, self_ty, shl, shr, stmt, stmt_decl, stmt_expr,
-             stmt_semi, struct_variant_kind, subtract, sty_box, sty_by_ref,
-             sty_region, sty_static, sty_uniq, sty_value, token_tree,
-             trait_method, trait_ref, tt_delim, tt_seq, tt_tok,
+             stmt_semi, struct_def, struct_variant_kind, subtract, sty_box,
+             sty_by_ref, sty_region, sty_static, sty_uniq, sty_value,
+             token_tree, trait_method, trait_ref, tt_delim, tt_seq, tt_tok,
              tt_nonterminal, ty, ty_, ty_bot, ty_box, ty_field, ty_fn,
              ty_infer, ty_mac, ty_method, ty_nil, ty_param, ty_param_bound,
              ty_path, ty_ptr, ty_rec, ty_rptr, ty_tup, ty_u32, ty_uniq,
@@ -2792,13 +2792,74 @@ class parser {
         }
     }
 
-    fn parse_enum_def(ty_params: ~[ast::ty_param]) -> enum_def {
+    fn parse_struct_def(path: @path) -> @struct_def {
+        let mut the_dtor: option<(blk, ~[attribute], codemap::span)> = none;
+        let mut ms: ~[@class_member] = ~[];
+        while self.token != token::RBRACE {
+            match self.parse_class_item(path) {
+                ctor_decl(*) => {
+                    self.span_fatal(copy self.span,
+                                    ~"deprecated explicit \
+                                      constructors are not allowed \
+                                      here");
+                }
+                dtor_decl(blk, attrs, s) => {
+                    match the_dtor {
+                        some((_, _, s_first)) => {
+                            self.span_note(s, ~"duplicate destructor \
+                                                declaration");
+                            self.span_fatal(copy s_first,
+                                            ~"first destructor \
+                                              declared here");
+                        }
+                        none => {
+                            the_dtor = some((blk, attrs, s));
+                        }
+                    }
+                }
+                members(mms) =>
+                    ms = vec::append(ms, mms)
+            }
+        }
+        self.bump();
+        let mut actual_dtor = do option::map(the_dtor) |dtor| {
+            let (d_body, d_attrs, d_s) = dtor;
+            {node: {id: self.get_id(),
+                    attrs: d_attrs,
+                    self_id: self.get_id(),
+                    body: d_body},
+             span: d_s}
+        };
+
+        return @{
+            traits: ~[],
+            members: ms,
+            ctor: none,
+            dtor: actual_dtor
+        };
+    }
+
+    fn parse_enum_def(ident: ast::ident, ty_params: ~[ast::ty_param])
+                   -> enum_def {
         let mut variants: ~[variant] = ~[];
         let mut all_nullary = true, have_disr = false;
+        let mut common_fields = none;
 
         while self.token != token::RBRACE {
             let variant_attrs = self.parse_outer_attributes();
             let vlo = self.span.lo;
+
+            // Is this a common field declaration?
+            if self.eat_keyword(~"struct") {
+                if common_fields.is_some() {
+                    self.fatal(~"duplicate declaration of shared fields");
+                }
+                self.expect(token::LBRACE);
+                let path = self.ident_to_path_tys(ident, ty_params);
+                common_fields = some(self.parse_struct_def(path));
+                again;
+            }
+
             let vis = self.parse_visibility();
             let ident = self.parse_value_ident();
             let mut args = ~[], disr_expr = none;
@@ -2807,51 +2868,7 @@ class parser {
                 // Parse a struct variant.
                 all_nullary = false;
                 let path = self.ident_to_path_tys(ident, ty_params);
-                let mut the_dtor: option<(blk, ~[attribute], codemap::span)> =
-                    none;
-                let mut ms: ~[@class_member] = ~[];
-                while self.token != token::RBRACE {
-                    match self.parse_class_item(path) {
-                        ctor_decl(*) => {
-                            self.span_fatal(copy self.span,
-                                            ~"deprecated explicit \
-                                              constructors are not allowed \
-                                              here");
-                        }
-                        dtor_decl(blk, attrs, s) => {
-                            match the_dtor {
-                                some((_, _, s_first)) => {
-                                    self.span_note(s, ~"duplicate destructor \
-                                                        declaration");
-                                    self.span_fatal(copy s_first,
-                                                    ~"first destructor \
-                                                      declared here");
-                                }
-                                none => {
-                                    the_dtor = some((blk, attrs, s));
-                                }
-                            }
-                        }
-                        members(mms) =>
-                            ms = vec::append(ms, mms)
-                    }
-                }
-                self.bump();
-                let mut actual_dtor = do option::map(the_dtor) |dtor| {
-                    let (d_body, d_attrs, d_s) = dtor;
-                    {node: {id: self.get_id(),
-                            attrs: d_attrs,
-                            self_id: self.get_id(),
-                            body: d_body},
-                     span: d_s}
-                };
-
-                kind = struct_variant_kind(@{
-                    traits: ~[],
-                    members: ms,
-                    ctor: none,
-                    dtor: actual_dtor
-                });
+                kind = struct_variant_kind(self.parse_struct_def(path));
             } else if self.token == token::LPAREN {
                 all_nullary = false;
                 let arg_tys = self.parse_unspanned_seq(
@@ -2883,7 +2900,7 @@ class parser {
                         enum");
         }
 
-        return enum_def({ variants: variants });
+        return enum_def({ variants: variants, common: common_fields });
     }
 
     fn parse_item_enum() -> item_info {
@@ -2905,12 +2922,13 @@ class parser {
                          id: self.get_id(),
                          disr_expr: none,
                          vis: public});
-            return (id, item_enum(enum_def({ variants: ~[variant] }),
+            return (id, item_enum(enum_def({ variants: ~[variant],
+                                             common: none }),
                                   ty_params), none);
         }
         self.expect(token::LBRACE);
 
-        let enum_definition = self.parse_enum_def(ty_params);
+        let enum_definition = self.parse_enum_def(id, ty_params);
         (id, item_enum(enum_definition, ty_params), none)
     }
 
diff --git a/src/test/run-pass/common-fields-trivial.rs b/src/test/run-pass/common-fields-trivial.rs
new file mode 100644
index 00000000000..c4feb893c10
--- /dev/null
+++ b/src/test/run-pass/common-fields-trivial.rs
@@ -0,0 +1,14 @@
+enum Foo {
+    struct {
+        x: int;
+        y: int;
+    }
+
+    Bar(int),
+    Baz(int)
+}
+
+fn main() {
+    let x = Bar(3);
+}
+