rustc: Translate tuple struct constructors

This commit is contained in:
Patrick Walton 2012-10-24 14:36:00 -07:00
parent ce23a99925
commit 599b4208fb
13 changed files with 193 additions and 49 deletions

View File

@ -1480,7 +1480,7 @@ type struct_def = {
dtor: Option<class_dtor>,
/* ID of the constructor. This is only used for tuple- or enum-like
* structs. */
ctor_id: node_id
ctor_id: Option<node_id>
};
/*

View File

@ -74,6 +74,7 @@ enum ast_node {
// Destructor for a class
node_dtor(~[ty_param], @class_dtor, def_id, @path),
node_block(blk),
node_struct_ctor(@struct_def, @item, @path)
}
type map = std::map::HashMap<node_id, ast_node>;
@ -284,6 +285,19 @@ fn map_struct_def(struct_def: @ast::struct_def, parent_node: ast_node,
for vec::each(struct_def.methods) |m| {
map_method(d_id, p, *m, cx);
}
// If this is a tuple-like struct, register the constructor.
match struct_def.ctor_id {
None => {}
Some(ctor_id) => {
match parent_node {
node_item(item, _) => {
cx.map.insert(ctor_id,
node_struct_ctor(struct_def, item, p));
}
_ => fail ~"struct def parent wasn't an item"
}
}
}
}
fn map_view_item(vi: @view_item, cx: ctx, _v: vt) {
@ -375,6 +389,9 @@ fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str {
Some(node_block(_)) => {
fmt!("block")
}
Some(node_struct_ctor(*)) => {
fmt!("struct_ctor")
}
}
}
// Local Variables:

View File

@ -589,6 +589,12 @@ fn view_path_id(p: @view_path) -> node_id {
}
}
/// Returns true if the given struct def is tuple-like; i.e. that its fields
/// are unnamed.
fn struct_def_is_tuple_like(struct_def: @ast::struct_def) -> bool {
struct_def.ctor_id.is_some()
}
// Local Variables:
// mode: rust
// fill-column: 78;

View File

@ -281,7 +281,7 @@ fn fold_struct_def(struct_def: @ast::struct_def, fld: ast_fold)
fields: vec::map(struct_def.fields, |f| fold_struct_field(*f, fld)),
methods: vec::map(struct_def.methods, |m| fld.fold_method(*m)),
dtor: dtor,
ctor_id: fld.new_id(struct_def.ctor_id)
ctor_id: option::map(&struct_def.ctor_id, |cid| fld.new_id(*cid))
};
}
@ -565,7 +565,7 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
methods: vec::map(struct_def.methods,
|m| fld.fold_method(*m)),
dtor: dtor,
ctor_id: fld.new_id(struct_def.ctor_id)
ctor_id: option::map(&struct_def.ctor_id, |c| fld.new_id(*c))
})
}

View File

@ -2659,9 +2659,11 @@ impl Parser {
let mut fields: ~[@struct_field];
let mut methods: ~[@method] = ~[];
let mut the_dtor: Option<(blk, ~[attribute], codemap::span)> = None;
let is_tuple_like;
if self.eat(token::LBRACE) {
// It's a record-like struct.
is_tuple_like = false;
fields = ~[];
while self.token != token::RBRACE {
match self.parse_class_item() {
@ -2694,6 +2696,7 @@ impl Parser {
self.bump();
} else if self.token == token::LPAREN {
// It's a tuple-like struct.
is_tuple_like = true;
fields = do self.parse_unspanned_seq(token::LPAREN, token::RPAREN,
seq_sep_trailing_allowed
(token::COMMA)) |p| {
@ -2708,6 +2711,7 @@ impl Parser {
self.expect(token::SEMI);
} else if self.eat(token::SEMI) {
// It's a unit-like struct.
is_tuple_like = true;
fields = ~[];
} else {
self.fatal(fmt!("expected `{`, `(`, or `;` after struct name \
@ -2723,13 +2727,14 @@ impl Parser {
body: d_body},
span: d_s}};
let _ = self.get_id(); // XXX: Workaround for crazy bug.
let new_id = self.get_id();
(class_name,
item_class(@{
traits: traits,
fields: move fields,
methods: move methods,
dtor: actual_dtor,
ctor_id: self.get_id()
ctor_id: if is_tuple_like { Some(new_id) } else { None }
}, ty_params),
None)
}
@ -3076,7 +3081,7 @@ impl Parser {
fields: move fields,
methods: move methods,
dtor: actual_dtor,
ctor_id: self.get_id()
ctor_id: Some(self.get_id())
};
}

View File

@ -311,6 +311,7 @@ mod special_idents {
const static : ident = ident { repr: 31u };
const intrinsic : ident = ident { repr: 32u };
const clownshoes_foreign_mod: ident = ident { repr: 33 };
const unnamed_field: ident = ident { repr: 34 };
}
struct ident_interner {

View File

@ -1187,12 +1187,14 @@ impl Resolver {
// If this struct is tuple-like or enum-like, define a name
// in the value namespace.
if struct_def.fields.len() == 0 ||
struct_def.fields[0].node.kind == unnamed_field {
name_bindings.define_value(
privacy,
def_class(local_def(struct_def.ctor_id)),
sp);
match struct_def.ctor_id {
None => {}
Some(ctor_id) => {
name_bindings.define_value(
privacy,
def_class(local_def(ctor_id)),
sp);
}
}
// Record the def ID of this struct.

View File

@ -1648,7 +1648,8 @@ fn trans_enum_variant(ccx: @crate_ctxt,
enum_id: ast::node_id,
variant: ast::variant,
args: ~[ast::variant_arg],
disr: int, is_degen: bool,
disr: int,
is_degen: bool,
param_substs: Option<param_substs>,
llfndecl: ValueRef) {
let _icx = ccx.insn_ctxt("trans_enum_variant");
@ -1698,6 +1699,51 @@ fn trans_enum_variant(ccx: @crate_ctxt,
finish_fn(fcx, lltop);
}
// NB: In theory this should be merged with the function above. But the AST
// structures are completely different, so very little code would be shared.
fn trans_tuple_struct(ccx: @crate_ctxt,
fields: ~[@ast::struct_field],
ctor_id: ast::node_id,
param_substs: Option<param_substs>,
llfndecl: ValueRef) {
let _icx = ccx.insn_ctxt("trans_tuple_struct");
// Translate struct fields to function arguments.
let fn_args = do fields.map |field| {
{
mode: ast::expl(ast::by_copy),
ty: field.node.ty,
ident: special_idents::arg,
id: field.node.id
}
};
let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, ctor_id, None,
param_substs, None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id));
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
for fields.eachi |i, field| {
let lldestptr = GEPi(bcx, fcx.llretptr, [0, 0, i]);
let llarg = match fcx.llargs.get(field.node.id) {
local_mem(x) => x,
_ => {
ccx.tcx.sess.bug(~"trans_tuple_struct: llarg wasn't \
local_mem")
}
};
let arg_ty = arg_tys[i].ty;
memmove_ty(bcx, lldestptr, llarg, arg_ty);
}
build_return(bcx);
finish_fn(fcx, lltop);
}
fn trans_class_dtor(ccx: @crate_ctxt, path: path,
body: ast::blk, dtor_id: ast::node_id,
psubsts: Option<param_substs>,
@ -1835,15 +1881,27 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
fn trans_struct_def(ccx: @crate_ctxt, struct_def: @ast::struct_def,
tps: ~[ast::ty_param], path: @ast_map::path,
ident: ast::ident, id: ast::node_id) {
// If there are type parameters, the destructor and constructor will be
// monomorphized, so we don't translate them here.
if tps.len() == 0u {
do option::iter(&struct_def.dtor) |dtor| {
trans_class_dtor(ccx, *path, dtor.node.body,
dtor.node.id, None, None, local_def(id));
};
}
// If there are ty params, the ctor will get monomorphized
// Translate the destructor.
do option::iter(&struct_def.dtor) |dtor| {
trans_class_dtor(ccx, *path, dtor.node.body,
dtor.node.id, None, None, local_def(id));
};
// Translate methods
// If this is a tuple-like struct, translate the constructor.
match struct_def.ctor_id {
None => {}
Some(ctor_id) => {
let llfndecl = get_item_val(ccx, ctor_id);
trans_tuple_struct(ccx, struct_def.fields, ctor_id, None,
llfndecl);
}
}
}
// Translate methods.
meth::trans_impl(ccx, *path, ident, struct_def.methods, tps, None, id);
}
@ -2128,8 +2186,25 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
set_inline_hint(llfn);
llfn
}
ast_map::node_struct_ctor(struct_def, struct_item, struct_path) => {
// Only register the constructor if this is a tuple-like struct.
match struct_def.ctor_id {
None => {
ccx.tcx.sess.bug(~"attempt to register a constructor of \
a non-tuple-like struct")
}
Some(ctor_id) => {
let llfn = register_fn(ccx, struct_item.span,
*struct_path, ctor_id);
set_inline_hint(llfn);
llfn
}
}
}
_ => {
ccx.sess.bug(~"get_item_val(): unexpected variant");
ccx.sess.bug(~"get_item_val(): unexpected variant")
}
};
if !(exprt || ccx.reachable.contains_key(id)) {

View File

@ -90,6 +90,9 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
vid).args.len() > 0u;
fn_callee(bcx, trans_fn_ref(bcx, vid, ref_expr.id))
}
ast::def_class(def_id) => {
fn_callee(bcx, trans_fn_ref(bcx, def_id, ref_expr.id))
}
ast::def_arg(*) |
ast::def_local(*) |
ast::def_binding(*) |
@ -99,7 +102,7 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
}
ast::def_mod(*) | ast::def_foreign_mod(*) |
ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) |
ast::def_use(*) | ast::def_class(*) | ast::def_typaram_binder(*) |
ast::def_use(*) | ast::def_typaram_binder(*) |
ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) => {
bcx.tcx().sess.span_bug(
ref_expr.span,

View File

@ -96,6 +96,7 @@ fn monomorphic_fn(ccx: @crate_ctxt,
ast_map::node_local(*) => {
ccx.tcx.sess.bug(~"Can't monomorphize a local")
}
ast_map::node_struct_ctor(_, i, pt) => (pt, i.ident, i.span)
};
// Look up the impl type if we're translating a default method.
@ -208,6 +209,18 @@ fn monomorphic_fn(ccx: @crate_ctxt,
impl_did_opt.get());
d
}
ast_map::node_struct_ctor(struct_def, _, _) => {
let d = mk_lldecl();
set_inline_hint(d);
base::trans_tuple_struct(ccx,
struct_def.fields,
option::expect(struct_def.ctor_id,
~"ast-mapped tuple struct \
didn't have a ctor id"),
psubsts,
d);
d
}
// Ugh -- but this ensures any new variants won't be forgotten
ast_map::node_expr(*) |

View File

@ -3630,6 +3630,10 @@ fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
syntax::parse::token::special_idents::literally_dtor))
}
ast_map::node_struct_ctor(_, item, path) => {
vec::append_one(*path, ast_map::path_name(item.ident))
}
ast_map::node_stmt(*) | ast_map::node_expr(*) |
ast_map::node_arg(*) | ast_map::node_local(*) |
ast_map::node_export(*) | ast_map::node_block(*) => {
@ -3874,7 +3878,13 @@ fn class_field_tys(fields: ~[@struct_field]) -> ~[field_ty] {
vis: visibility,
mutability: mutability});
}
unnamed_field => {}
unnamed_field => {
rslt.push({ident:
syntax::parse::token::special_idents::unnamed_field,
id: ast_util::local_def(field.node.id),
vis: ast::public,
mutability: ast::class_immutable});
}
}
}
rslt

View File

@ -597,35 +597,40 @@ fn convert_struct(ccx: @crate_ctxt,
// If this struct is enum-like or tuple-like, create the type of its
// constructor.
if struct_def.fields.len() == 0 {
// Enum-like.
write_ty_to_tcx(tcx, struct_def.ctor_id, selfty);
tcx.tcache.insert(local_def(struct_def.ctor_id), tpt);
} else if struct_def.fields[0].node.kind == ast::unnamed_field {
// Tuple-like.
let ctor_fn_ty = ty::mk_fn(tcx, FnTyBase {
meta: FnMeta {
purity: ast::pure_fn,
proto: ty::proto_bare,
bounds: @~[],
ret_style: ast::return_val,
},
sig: FnSig {
inputs: do struct_def.fields.map |field| {
{
mode: ast::expl(ast::by_copy),
ty: ccx.tcx.tcache.get(local_def(field.node.id)).ty
match struct_def.ctor_id {
None => {}
Some(ctor_id) => {
if struct_def.fields.len() == 0 {
// Enum-like.
write_ty_to_tcx(tcx, ctor_id, selfty);
tcx.tcache.insert(local_def(ctor_id), tpt);
} else if struct_def.fields[0].node.kind == ast::unnamed_field {
// Tuple-like.
let ctor_fn_ty = ty::mk_fn(tcx, FnTyBase {
meta: FnMeta {
purity: ast::pure_fn,
proto: ty::proto_bare,
bounds: @~[],
ret_style: ast::return_val,
},
sig: FnSig {
inputs: do struct_def.fields.map |field| {
{
mode: ast::expl(ast::by_copy),
ty: ccx.tcx.tcache.get(local_def(field.node.id)).ty
}
},
output: selfty
}
},
output: selfty
});
write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty);
tcx.tcache.insert(local_def(ctor_id), {
bounds: tpt.bounds,
region_param: tpt.region_param,
ty: ctor_fn_ty
});
}
});
write_ty_to_tcx(tcx, struct_def.ctor_id, ctor_fn_ty);
tcx.tcache.insert(local_def(struct_def.ctor_id), {
bounds: tpt.bounds,
region_param: tpt.region_param,
ty: ctor_fn_ty
});
}
}
}

View File

@ -0,0 +1,7 @@
struct Foo(int, int);
fn main() {
let x = Foo(1, 2);
io::println(fmt!("%?", x));
}