rustc: Add stub support for struct variants to the AST

This commit is contained in:
Patrick Walton 2012-08-07 14:24:04 -07:00
parent bc267c696c
commit 727c7c7499
14 changed files with 232 additions and 139 deletions

View file

@ -632,7 +632,13 @@ type foreign_mod =
type variant_arg = {ty: @ty, id: node_id};
#[auto_serialize]
type variant_ = {name: ident, attrs: ~[attribute], args: ~[variant_arg],
enum variant_kind {
tuple_variant_kind(~[variant_arg]),
struct_variant_kind
}
#[auto_serialize]
type variant_ = {name: ident, attrs: ~[attribute], kind: variant_kind,
id: node_id, disr_expr: option<@expr>, vis: visibility};
#[auto_serialize]

View file

@ -187,12 +187,13 @@ fn is_exported(i: ident, m: _mod) -> bool {
for m.items.each |it| {
if it.ident == i { local = true; }
match it.node {
item_enum(variants, _) => for variants.each |v| {
if v.node.name == i {
local = true;
parent_enum = some(/* FIXME (#2543) */ copy it.ident);
item_enum(variants, _) =>
for variants.each |v| {
if v.node.name == i {
local = true;
parent_enum = some(/* FIXME (#2543) */ copy it.ident);
}
}
},
_ => ()
}
if local { break; }

View file

@ -830,43 +830,51 @@ fn ser_enum(cx: ext_ctxt, tps: ser_tps_map, e_name: ast::ident,
let variant = variants[vidx];
let v_span = variant.span;
let v_name = variant.node.name;
let variant_tys = vec::map(variant.node.args, |a| a.ty);
ser_variant(
cx, tps, variant_tys, v_span, cx.clone(s),
match variant.node.kind {
ast::tuple_variant_kind(args) => {
let variant_tys = vec::map(args, |a| a.ty);
// Generate pattern var(v1, v2, v3)
|pats| {
if vec::is_empty(pats) {
ast::pat_ident(ast::bind_by_implicit_ref,
cx.path(v_span, ~[v_name]),
none)
} else {
ast::pat_enum(cx.path(v_span, ~[v_name]), some(pats))
}
},
ser_variant(
cx, tps, variant_tys, v_span, cx.clone(s),
// Generate body s.emit_enum_variant("foo", 0u,
// 3u, {|| blk })
|-s, blk| {
let v_name = cx.lit_str(v_span, v_name);
let v_id = cx.lit_uint(v_span, vidx);
let sz = cx.lit_uint(v_span, vec::len(variant_tys));
let body = cx.lambda(blk);
#ast[expr]{
$(s).emit_enum_variant($(v_name), $(v_id),
$(sz), $(body))
}
},
// Generate pattern var(v1, v2, v3)
|pats| {
if vec::is_empty(pats) {
ast::pat_ident(ast::bind_by_implicit_ref,
cx.path(v_span, ~[v_name]),
none)
} else {
ast::pat_enum(cx.path(v_span, ~[v_name]),
some(pats))
}
},
// Generate s.emit_enum_variant_arg(i, {|| blk })
|-s, i, blk| {
let idx = cx.lit_uint(v_span, i);
let body = cx.lambda(blk);
#ast[expr]{
$(s).emit_enum_variant_arg($(idx), $(body))
}
})
// Generate body s.emit_enum_variant("foo", 0u,
// 3u, {|| blk })
|-s, blk| {
let v_name = cx.lit_str(v_span, v_name);
let v_id = cx.lit_uint(v_span, vidx);
let sz = cx.lit_uint(v_span, vec::len(variant_tys));
let body = cx.lambda(blk);
#ast[expr]{
$(s).emit_enum_variant($(v_name), $(v_id),
$(sz), $(body))
}
},
// Generate s.emit_enum_variant_arg(i, {|| blk })
|-s, i, blk| {
let idx = cx.lit_uint(v_span, i);
let body = cx.lambda(blk);
#ast[expr]{
$(s).emit_enum_variant_arg($(idx), $(body))
}
})
}
_ =>
fail ~"struct variants unimplemented for auto serialize"
}
};
let lam = cx.lambda(cx.blk(e_span, ~[cx.alt_stmt(arms, e_span, v)]));
let e_name = cx.lit_str(e_span, e_name);
@ -881,24 +889,32 @@ fn deser_enum(cx: ext_ctxt, tps: deser_tps_map, e_name: ast::ident,
let variant = variants[vidx];
let v_span = variant.span;
let v_name = variant.node.name;
let tys = vec::map(variant.node.args, |a| a.ty);
let arg_exprs = do vec::from_fn(vec::len(tys)) |i| {
let idx = cx.lit_uint(v_span, i);
let body = deser_lambda(cx, tps, tys[i], cx.clone(d));
#ast{ $(d).read_enum_variant_arg($(idx), $(body)) }
};
let body;
match variant.node.kind {
ast::tuple_variant_kind(args) => {
let tys = vec::map(args, |a| a.ty);
let body = {
if vec::is_empty(tys) {
// for a nullary variant v, do "v"
cx.var_ref(v_span, v_name)
} else {
// for an n-ary variant v, do "v(a_1, ..., a_n)"
cx.expr(v_span, ast::expr_call(
cx.var_ref(v_span, v_name), arg_exprs, false))
let arg_exprs = do vec::from_fn(vec::len(tys)) |i| {
let idx = cx.lit_uint(v_span, i);
let body = deser_lambda(cx, tps, tys[i], cx.clone(d));
#ast{ $(d).read_enum_variant_arg($(idx), $(body)) }
};
body = {
if vec::is_empty(tys) {
// for a nullary variant v, do "v"
cx.var_ref(v_span, v_name)
} else {
// for an n-ary variant v, do "v(a_1, ..., a_n)"
cx.expr(v_span, ast::expr_call(
cx.var_ref(v_span, v_name), arg_exprs, false))
}
};
}
};
ast::struct_variant_kind =>
fail ~"struct variants unimplemented"
}
{pats: ~[@{id: cx.next_id(),
node: ast::pat_lit(cx.lit_uint(v_span, vidx)),

View file

@ -254,7 +254,7 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
{node: {name: name,
attrs: ~[],
args: args,
kind: ast::tuple_variant_kind(args),
id: self.next_id(),
disr_expr: none,
vis: ast::public},

View file

@ -541,7 +541,15 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
return {ty: fld.fold_ty(va.ty), id: fld.new_id(va.id)};
}
let fold_variant_arg = |x| fold_variant_arg_(x, fld);
let args = vec::map(v.args, fold_variant_arg);
let kind;
match v.kind {
tuple_variant_kind(variant_args) =>
kind = tuple_variant_kind(vec::map(variant_args,
fold_variant_arg)),
struct_variant_kind =>
kind = struct_variant_kind
}
let fold_attribute = |x| fold_attribute_(x, fld);
let attrs = vec::map(v.attrs, fold_attribute);
@ -552,7 +560,8 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
};
return {name: /* FIXME (#2543) */ copy v.name,
attrs: attrs,
args: args, id: fld.new_id(v.id),
kind: kind,
id: fld.new_id(v.id),
disr_expr: de,
vis: v.vis};
}

View file

@ -49,14 +49,14 @@ import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
return_val, self_ty, shl, shr, stmt, stmt_decl, stmt_expr,
stmt_semi, subtract, sty_box, sty_by_ref, sty_region, 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, 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};
tt_tok, tt_nonterminal, tuple_variant_kind, 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, 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;
@ -2830,7 +2830,8 @@ class parser {
spanned(ty.span.lo, ty.span.hi,
{name: id,
attrs: ~[],
args: ~[{ty: ty, id: self.get_id()}],
kind: tuple_variant_kind
(~[{ty: ty, id: self.get_id()}]),
id: self.get_id(),
disr_expr: none,
vis: public});
@ -2861,7 +2862,7 @@ class parser {
}
let vr = {name: ident, attrs: variant_attrs,
args: args, id: self.get_id(),
kind: tuple_variant_kind(args), id: self.get_id(),
disr_expr: disr_expr, vis: vis};
vec::push(variants, spanned(vlo, self.last_span.hi, vr));

View file

@ -488,21 +488,31 @@ fn print_item(s: ps, &&item: @ast::item) {
end(s); // end the outer ibox
}
ast::item_enum(variants, params) => {
let newtype =
let mut newtype =
vec::len(variants) == 1u &&
str::eq(item.ident, variants[0].node.name) &&
vec::len(variants[0].node.args) == 1u;
str::eq(item.ident, variants[0].node.name);
if newtype {
match variants[0].node.kind {
ast::tuple_variant_kind(args) if args.len() == 1 => {}
_ => newtype = false
}
}
if newtype {
ibox(s, indent_unit);
word_space(s, ~"enum");
} else { head(s, ~"enum"); }
} else {
head(s, ~"enum");
}
word(s.s, *item.ident);
print_type_params(s, params);
space(s.s);
if newtype {
word_space(s, ~"=");
print_type(s, variants[0].node.args[0].ty);
match variants[0].node.kind {
ast::tuple_variant_kind(args) => print_type(s, args[0].ty),
_ => fail ~"newtype syntax with struct?"
}
word(s.s, ~";");
end(s);
} else {
@ -680,13 +690,18 @@ fn print_tt(s: ps, tt: ast::token_tree) {
fn print_variant(s: ps, v: ast::variant) {
word(s.s, *v.node.name);
if vec::len(v.node.args) > 0u {
popen(s);
fn print_variant_arg(s: ps, arg: ast::variant_arg) {
print_type(s, arg.ty);
match v.node.kind {
ast::tuple_variant_kind(args) => {
if vec::len(args) > 0u {
popen(s);
fn print_variant_arg(s: ps, arg: ast::variant_arg) {
print_type(s, arg.ty);
}
commasep(s, consistent, args, print_variant_arg);
pclose(s);
}
}
commasep(s, consistent, v.node.args, print_variant_arg);
pclose(s);
ast::struct_variant_kind => {}
}
match v.node.disr_expr {
some(d) => {

View file

@ -135,7 +135,11 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
item_enum(variants, tps) => {
v.visit_ty_params(tps, e, v);
for variants.each |vr| {
for vr.node.args.each |va| { v.visit_ty(va.ty, e, v); }
match vr.node.kind {
tuple_variant_kind(variant_args) =>
for variant_args.each |va| { v.visit_ty(va.ty, e, v); },
struct_variant_kind => {}
}
}
}
item_impl(tps, traits, ty, methods) => {

View file

@ -362,8 +362,12 @@ fn encode_enum_variant_info(ecx: @encode_ctxt, ebml_w: ebml::writer,
encode_parent_item(ebml_w, local_def(id));
encode_type(ecx, ebml_w,
node_id_to_type(ecx.tcx, variant.node.id));
if vec::len(variant.node.args) > 0u && ty_params.len() == 0u {
encode_symbol(ecx, ebml_w, variant.node.id);
match variant.node.kind {
ast::tuple_variant_kind(args)
if args.len() > 0 && ty_params.len() == 0 => {
encode_symbol(ecx, ebml_w, variant.node.id);
}
ast::tuple_variant_kind(_) | ast::struct_variant_kind => {}
}
encode_discriminant(ecx, ebml_w, variant.node.id);
if vi[i].disr_val != disr_val {

View file

@ -2173,8 +2173,14 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id,
tv.id.node == fn_id.node}));
let d = mk_lldecl();
set_inline_hint(d);
trans_enum_variant(ccx, enum_item.id, v, this_tv.disr_val,
(*tvs).len() == 1u, psubsts, d);
match v.node.kind {
ast::tuple_variant_kind(args) => {
trans_enum_variant(ccx, enum_item.id, v, args,
this_tv.disr_val, (*tvs).len() == 1u,
psubsts, d);
}
ast::struct_variant_kind => {}
}
d
}
ast_map::node_method(mth, impl_def_id, _) => {
@ -4671,13 +4677,16 @@ fn trans_fn(ccx: @crate_ctxt,
}
}
fn trans_enum_variant(ccx: @crate_ctxt, enum_id: ast::node_id,
variant: ast::variant, disr: int, is_degen: bool,
fn trans_enum_variant(ccx: @crate_ctxt,
enum_id: ast::node_id,
variant: ast::variant,
args: ~[ast::variant_arg],
disr: int, is_degen: bool,
param_substs: option<param_substs>,
llfndecl: ValueRef) {
let _icx = ccx.insn_ctxt(~"trans_enum_variant");
// Translate variant arguments to function arguments.
let fn_args = vec::map(variant.node.args, |varg|
let fn_args = vec::map(args, |varg|
{mode: ast::expl(ast::by_copy),
ty: varg.ty,
ident: @~"arg",
@ -4705,7 +4714,7 @@ fn trans_enum_variant(ccx: @crate_ctxt, enum_id: ast::node_id,
};
let t_id = local_def(enum_id);
let v_id = local_def(variant.node.id);
for vec::eachi(variant.node.args) |i, va| {
for vec::eachi(args) |i, va| {
let lldestptr = GEP_enum(bcx, llblobptr, t_id, v_id,
ty_param_substs, i);
// If this argument to this function is a enum, it'll have come in to
@ -4867,11 +4876,16 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
let vi = ty::enum_variants(ccx.tcx, local_def(item.id));
let mut i = 0;
for vec::each(variants) |variant| {
if variant.node.args.len() > 0u {
let llfn = get_item_val(ccx, variant.node.id);
trans_enum_variant(ccx, item.id, variant,
vi[i].disr_val, degen,
none, llfn);
match variant.node.kind {
ast::tuple_variant_kind(args) if args.len() > 0 => {
let llfn = get_item_val(ccx, variant.node.id);
trans_enum_variant(ccx, item.id, variant, args,
vi[i].disr_val, degen,
none, llfn);
}
ast::tuple_variant_kind(_) | ast::struct_variant_kind => {
// Nothing to do.
}
}
i += 1;
}
@ -5166,15 +5180,23 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
}
ast_map::node_variant(v, enm, pth) => {
assert v.node.args.len() != 0u;
let pth = vec::append(*pth,
~[path_name(enm.ident),
path_name(v.node.name)]);
let llfn = match check enm.node {
ast::item_enum(_, _) => {
register_fn(ccx, v.span, pth, id)
}
};
let llfn;
match v.node.kind {
ast::tuple_variant_kind(args) => {
assert args.len() != 0u;
let pth = vec::append(*pth,
~[path_name(enm.ident),
path_name(v.node.name)]);
llfn = match check enm.node {
ast::item_enum(_, _) => {
register_fn(ccx, v.span, pth, id)
}
};
}
ast::struct_variant_kind => {
fail ~"struct unexpected in get_item_val"
}
}
set_inline_hint(llfn);
llfn
}

View file

@ -2837,28 +2837,37 @@ fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[variant_info] {
ast_map::node_item(@{node: ast::item_enum(variants, _), _}, _) => {
let mut disr_val = -1;
@vec::map(variants, |variant| {
let ctor_ty = node_id_to_type(cx, variant.node.id);
let arg_tys = {
if vec::len(variant.node.args) > 0u {
ty_fn_args(ctor_ty).map(|a| a.ty)
} else { ~[] }
};
match variant.node.disr_expr {
some (ex) => {
// FIXME: issue #1417
disr_val = match const_eval::eval_const_expr(cx, ex) {
const_eval::const_int(val) =>val as int,
_ => cx.sess.bug(~"tag_variants: bad disr expr")
match variant.node.kind {
ast::tuple_variant_kind(args) => {
let ctor_ty = node_id_to_type(cx, variant.node.id);
let arg_tys = {
if vec::len(args) > 0u {
ty_fn_args(ctor_ty).map(|a| a.ty)
} else {
~[]
}
};
match variant.node.disr_expr {
some (ex) => {
// FIXME: issue #1417
disr_val = match const_eval::eval_const_expr(cx,
ex) {
const_eval::const_int(val) => val as int,
_ => cx.sess.bug(~"tag_variants: bad disr expr")
}
}
_ => disr_val += 1
}
@{args: arg_tys,
ctor_ty: ctor_ty,
name: variant.node.name,
id: ast_util::local_def(variant.node.id),
disr_val: disr_val
}
}
}
_ => disr_val += 1
ast::struct_variant_kind =>
fail ~"struct variant kinds unimpl in enum_variants"
}
@{args: arg_tys,
ctor_ty: ctor_ty,
name: variant.node.name,
id: ast_util::local_def(variant.node.id),
disr_val: disr_val
}
})
}
_ => cx.sess.bug(~"tag_variants: id not bound to an enum")

View file

@ -2073,9 +2073,13 @@ fn check_enum_variants(ccx: @crate_ctxt,
}
vec::push(disr_vals, disr_val);
let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id);
let arg_tys = if v.node.args.len() > 0u {
ty::ty_fn_args(ctor_ty).map(|a| a.ty)
} else { ~[] };
let arg_tys;
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 =>
arg_tys = ~[]
};
vec::push(variants, @{args: arg_tys, ctor_ty: ctor_ty,
name: v.node.name, id: local_def(v.node.id),
disr_val: disr_val});

View file

@ -111,7 +111,6 @@ fn get_base_type_def_id(inference_context: infer_ctxt,
class CoherenceInfo {
// Contains implementations of methods that are inherent to a type.
// Methods in these implementations don't need to be exported.
let inherent_methods: hashmap<def_id,@dvec<@Impl>>;
// Contains implementations of methods associated with a trait. For these,

View file

@ -115,20 +115,23 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
for variants.each |variant| {
// Nullary enum constructors get turned into constants; n-ary enum
// constructors get turned into functions.
let result_ty = if vec::len(variant.node.args) == 0u {
enum_ty
} else {
let rs = type_rscope(rp);
let args = variant.node.args.map(|va| {
let arg_ty = ccx.to_ty(rs, va.ty);
{mode: ast::expl(ast::by_copy), ty: arg_ty}
});
ty::mk_fn(tcx, {purity: ast::pure_fn,
proto: ast::proto_box,
bounds: @~[],
inputs: args,
output: enum_ty,
ret_style: ast::return_val})
let result_ty;
match variant.node.kind {
ast::tuple_variant_kind(args) if args.len() > 0 => {
let rs = type_rscope(rp);
let args = args.map(|va| {
let arg_ty = ccx.to_ty(rs, va.ty);
{mode: ast::expl(ast::by_copy), ty: arg_ty}
});
result_ty = ty::mk_fn(tcx, {purity: ast::pure_fn,
proto: ast::proto_box,
bounds: @~[],
inputs: args,
output: enum_ty,
ret_style: ast::return_val});
}
ast::tuple_variant_kind(_) | ast::struct_variant_kind =>
result_ty = enum_ty
};
let tpt = {bounds: ty_param_bounds(ccx, ty_params),
rp: rp,