From 5ce3281a624c0620f1b6f4e21c15e4a6a17a1dc5 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 7 Aug 2012 18:54:44 -0700 Subject: [PATCH] rustc: Parse variant structs; add a trivial test case --- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/auto_serialize.rs | 2 +- src/libsyntax/fold.rs | 17 +++- src/libsyntax/parse/parser.rs | 87 ++++++++++++++++---- src/libsyntax/print/pprust.rs | 7 +- src/libsyntax/visit.rs | 10 ++- src/rustc/metadata/encoder.rs | 2 +- src/rustc/middle/trans/base.rs | 11 ++- src/rustc/middle/ty.rs | 2 +- src/rustc/middle/typeck/check.rs | 2 +- src/rustc/middle/typeck/collect.rs | 2 +- src/test/run-pass/variant-structs-trivial.rs | 6 ++ 12 files changed, 116 insertions(+), 34 deletions(-) create mode 100644 src/test/run-pass/variant-structs-trivial.rs diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 4a9cefe7d1b..f1c5f63bd1d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -636,7 +636,7 @@ type variant_arg = {ty: @ty, id: node_id}; #[auto_serialize] enum variant_kind { tuple_variant_kind(~[variant_arg]), - struct_variant_kind + struct_variant_kind(@struct_def) } #[auto_serialize] diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs index 4ce017eeae9..20cc04b2c79 100644 --- a/src/libsyntax/ext/auto_serialize.rs +++ b/src/libsyntax/ext/auto_serialize.rs @@ -912,7 +912,7 @@ fn deser_enum(cx: ext_ctxt, tps: deser_tps_map, e_name: ast::ident, } }; } - ast::struct_variant_kind => + ast::struct_variant_kind(*) => fail ~"struct variants unimplemented" } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 36c80cb3d5f..22713618222 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -549,8 +549,21 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ { tuple_variant_kind(variant_args) => kind = tuple_variant_kind(vec::map(variant_args, fold_variant_arg)), - struct_variant_kind => - kind = struct_variant_kind + struct_variant_kind(struct_def) => { + 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}}; + kind = struct_variant_kind(@{ + traits: ~[], + members: vec::map(struct_def.members, + |x| fld.fold_class_item(x)), + ctor: none, + dtor: dtor + }) + } } let fold_attribute = |x| fold_attribute_(x, fld); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 46ed906900c..6f19f272331 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,24 +43,21 @@ import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute, match_nonterminal, match_seq, match_tok, method, mode, mt, mul, mutability, neg, noreturn, not, pat, pat_box, pat_enum, pat_ident, pat_lit, pat_range, pat_rec, pat_struct, pat_tup, - pat_uniq, - pat_wild, path, private, proto, proto_bare, 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, - 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, + pat_uniq, pat_wild, path, private, proto, proto_bare, + 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, 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, ty_vec, - ty_fixed_length, tuple_variant_kind, - unchecked_blk, uniq, unsafe_blk, unsafe_fn, - variant, view_item, view_item_, view_item_export, - view_item_import, view_item_use, view_path, view_path_glob, - view_path_list, view_path_simple, visibility, vstore, vstore_box, - vstore_fixed, vstore_slice, vstore_uniq}; + ty_path, ty_ptr, ty_rec, ty_rptr, ty_tup, ty_u32, ty_uniq, + ty_vec, ty_fixed_length, tuple_variant_kind, unchecked_blk, uniq, + unsafe_blk, unsafe_fn, variant, view_item, view_item_, + view_item_export, view_item_import, view_item_use, view_path, + view_path_glob, view_path_list, view_path_simple, visibility, + vstore, vstore_box, vstore_fixed, vstore_slice, vstore_uniq}; export file_type; export parser; @@ -2877,7 +2874,57 @@ class parser { let vis = self.parse_visibility(); let ident = self.parse_value_ident(); let mut args = ~[], disr_expr = none; - if self.token == token::LPAREN { + let kind; + if self.eat(token::LBRACE) { + // 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 + }); + } else if self.token == token::LPAREN { all_nullary = false; let arg_tys = self.parse_unspanned_seq( token::LPAREN, token::RPAREN, @@ -2886,13 +2933,17 @@ class parser { for arg_tys.each |ty| { vec::push(args, {ty: ty, id: self.get_id()}); } + kind = tuple_variant_kind(args); } else if self.eat(token::EQ) { have_disr = true; disr_expr = some(self.parse_expr()); + kind = tuple_variant_kind(args); + } else { + kind = tuple_variant_kind(~[]); } let vr = {name: ident, attrs: variant_attrs, - kind: tuple_variant_kind(args), id: self.get_id(), + kind: kind, id: self.get_id(), disr_expr: disr_expr, vis: vis}; vec::push(variants, spanned(vlo, self.last_span.hi, vr)); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d9c85b8c72b..4b23fbf74a9 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -694,9 +694,9 @@ fn print_tt(s: ps, tt: ast::token_tree) { } fn print_variant(s: ps, v: ast::variant) { - word(s.s, *v.node.name); match v.node.kind { ast::tuple_variant_kind(args) => { + word(s.s, *v.node.name); if vec::len(args) > 0u { popen(s); fn print_variant_arg(s: ps, arg: ast::variant_arg) { @@ -706,7 +706,10 @@ fn print_variant(s: ps, v: ast::variant) { pclose(s); } } - ast::struct_variant_kind => {} + ast::struct_variant_kind(struct_def) => { + head(s, ~""); + print_struct(s, struct_def, ~[], v.node.name, v.span); + } } match v.node.disr_expr { some(d) => { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 142656aa7c3..a47685dd42c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -140,9 +140,13 @@ fn visit_item(i: @item, e: E, v: vt) { v.visit_ty_params(tps, e, v); for variants.each |vr| { match vr.node.kind { - tuple_variant_kind(variant_args) => - for variant_args.each |va| { v.visit_ty(va.ty, e, v); }, - struct_variant_kind => {} + tuple_variant_kind(variant_args) => { + for variant_args.each |va| { v.visit_ty(va.ty, e, v); } + } + struct_variant_kind(struct_def) => { + v.visit_struct_def(struct_def, vr.node.name, tps, + vr.node.id, e, v); + } } } } diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index a0e9c875f06..07d12a12866 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -398,7 +398,7 @@ fn encode_enum_variant_info(ecx: @encode_ctxt, ebml_w: ebml::writer, if args.len() > 0 && ty_params.len() == 0 => { encode_symbol(ecx, ebml_w, variant.node.id); } - ast::tuple_variant_kind(_) | ast::struct_variant_kind => {} + ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) => {} } encode_discriminant(ecx, ebml_w, variant.node.id); if vi[i].disr_val != disr_val { diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 2c7885a3f0c..fd13d8fa1ef 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -2187,7 +2187,8 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, this_tv.disr_val, (*tvs).len() == 1u, psubsts, d); } - ast::struct_variant_kind => {} + ast::struct_variant_kind(_) => + ccx.tcx.sess.bug(~"can't monomorphize struct variants") } d } @@ -4894,9 +4895,13 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) { vi[i].disr_val, degen, none, llfn); } - ast::tuple_variant_kind(_) | ast::struct_variant_kind => { + ast::tuple_variant_kind(_) => { // Nothing to do. } + ast::struct_variant_kind(struct_def) => { + trans_struct_def(ccx, struct_def, tps, path, + variant.node.name, variant.node.id); + } } i += 1; } @@ -5210,7 +5215,7 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef { } }; } - ast::struct_variant_kind => { + ast::struct_variant_kind(_) => { fail ~"struct unexpected in get_item_val" } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index aa33f355f22..ad7824fabe5 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -2868,7 +2868,7 @@ fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[variant_info] { disr_val: disr_val } } - ast::struct_variant_kind => + ast::struct_variant_kind(_) => fail ~"struct variant kinds unimpl in enum_variants" } }) diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 0c59559db76..ec7e642c09d 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -2081,7 +2081,7 @@ fn check_enum_variants(ccx: @crate_ctxt, match v.node.kind { ast::tuple_variant_kind(args) if args.len() > 0u => arg_tys = ty::ty_fn_args(ctor_ty).map(|a| a.ty), - ast::tuple_variant_kind(_) | ast::struct_variant_kind => + ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) => arg_tys = ~[] }; vec::push(variants, @{args: arg_tys, ctor_ty: ctor_ty, diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs index abbe5eb40ee..64021f216c3 100644 --- a/src/rustc/middle/typeck/collect.rs +++ b/src/rustc/middle/typeck/collect.rs @@ -131,7 +131,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt, output: enum_ty, ret_style: ast::return_val}); } - ast::tuple_variant_kind(_) | ast::struct_variant_kind => + ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) => result_ty = enum_ty }; let tpt = {bounds: ty_param_bounds(ccx, ty_params), diff --git a/src/test/run-pass/variant-structs-trivial.rs b/src/test/run-pass/variant-structs-trivial.rs new file mode 100644 index 00000000000..c8c6a88ddf2 --- /dev/null +++ b/src/test/run-pass/variant-structs-trivial.rs @@ -0,0 +1,6 @@ +enum Foo { + Bar { x: int; }, + Baz { y: int; } +} + +fn main() { }