rustc: Translate tuple struct constructors
This commit is contained in:
parent
ce23a99925
commit
599b4208fb
@ -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>
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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)) {
|
||||
|
@ -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,
|
||||
|
@ -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(*) |
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
7
src/test/run-pass/tuple-struct-construct.rs
Normal file
7
src/test/run-pass/tuple-struct-construct.rs
Normal file
@ -0,0 +1,7 @@
|
||||
struct Foo(int, int);
|
||||
|
||||
fn main() {
|
||||
let x = Foo(1, 2);
|
||||
io::println(fmt!("%?", x));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user