Skip to content

Commit

Permalink
Merge pull request #3857 from pcwalton/tuple-struct-ctors
Browse files Browse the repository at this point in the history
rustc: Translate tuple struct constructors. r=brson
  • Loading branch information
pcwalton committed Oct 25, 2012
2 parents ce23a99 + 599b420 commit d6b3d65
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 48 deletions.
2 changes: 1 addition & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
};

/*
Expand Down
17 changes: 17 additions & 0 deletions src/libsyntax/ast_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions src/libsyntax/ast_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
};
}

Expand Down Expand Up @@ -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))
})
}

Expand Down
9 changes: 7 additions & 2 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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| {
Expand All @@ -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 \
Expand All @@ -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)
}
Expand Down Expand Up @@ -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())
};
}

Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/parse/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
14 changes: 8 additions & 6 deletions src/rustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
91 changes: 83 additions & 8 deletions src/rustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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));
};
// 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));
};

// 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);
}
}
}
// If there are ty params, the ctor will get monomorphized

// Translate methods
// Translate methods.
meth::trans_impl(ccx, *path, ident, struct_def.methods, tps, None, id);
}

Expand Down Expand Up @@ -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)) {
Expand Down
5 changes: 4 additions & 1 deletion src/rustc/middle/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(*) |
Expand All @@ -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,
Expand Down
13 changes: 13 additions & 0 deletions src/rustc/middle/trans/monomorphize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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(*) |
Expand Down
12 changes: 11 additions & 1 deletion src/rustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(*) => {
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit d6b3d65

Please sign in to comment.