Skip to content

Commit 61bb357

Browse files
committed
rustc: Implement construction of monomorphic struct-like variants. r=nmatsakis
1 parent 759e1c1 commit 61bb357

File tree

9 files changed

+303
-73
lines changed

9 files changed

+303
-73
lines changed

src/rustc/middle/privacy.rs

+28-4
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
use /*mod*/ syntax::ast;
55
use /*mod*/ syntax::visit;
6-
use syntax::ast::{expr_field, expr_struct, ident, item_class, item_impl};
7-
use syntax::ast::{item_trait, local_crate, node_id, pat_struct, private};
8-
use syntax::ast::{provided, required};
6+
use syntax::ast::{def_variant, expr_field, expr_struct, ident, item_class};
7+
use syntax::ast::{item_impl, item_trait, local_crate, node_id, pat_struct};
8+
use syntax::ast::{private, provided, required};
99
use syntax::ast_map::{node_item, node_method};
10-
use ty::ty_class;
10+
use ty::{ty_class, ty_enum};
1111
use typeck::{method_map, method_origin, method_param, method_self};
1212
use typeck::{method_static, method_trait};
1313

@@ -188,6 +188,30 @@ fn check_crate(tcx: ty::ctxt, method_map: &method_map, crate: @ast::crate) {
188188
}
189189
}
190190
}
191+
ty_enum(id, _) => {
192+
if id.crate != local_crate ||
193+
!privileged_items.contains(&(id.node)) {
194+
match tcx.def_map.get(expr.id) {
195+
def_variant(_, variant_id) => {
196+
for fields.each |field| {
197+
debug!("(privacy checking) \
198+
checking field in \
199+
struct variant \
200+
literal");
201+
check_field(expr.span, variant_id,
202+
field.node.ident);
203+
}
204+
}
205+
_ => {
206+
tcx.sess.span_bug(expr.span,
207+
~"resolve didn't \
208+
map enum struct \
209+
constructor to a \
210+
variant def");
211+
}
212+
}
213+
}
214+
}
191215
_ => {
192216
tcx.sess.span_bug(expr.span, ~"struct expr \
193217
didn't have \

src/rustc/middle/trans/alt.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -909,7 +909,7 @@ fn compile_submatch(bcx: block,
909909
let rec_fields = collect_record_or_struct_fields(m, col);
910910
if rec_fields.len() > 0 {
911911
let pat_ty = node_id_type(bcx, pat_id);
912-
do expr::with_field_tys(tcx, pat_ty) |_has_dtor, field_tys| {
912+
do expr::with_field_tys(tcx, pat_ty, None) |_has_dtor, field_tys| {
913913
let rec_vals = rec_fields.map(|field_name| {
914914
let ix = ty::field_idx_strict(tcx, *field_name, field_tys);
915915
GEPi(bcx, val, struct_field(ix))
@@ -1257,7 +1257,7 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
12571257
ast::pat_rec(fields, _) | ast::pat_struct(_, fields, _) => {
12581258
let tcx = bcx.tcx();
12591259
let pat_ty = node_id_type(bcx, pat.id);
1260-
do expr::with_field_tys(tcx, pat_ty) |_has_dtor, field_tys| {
1260+
do expr::with_field_tys(tcx, pat_ty, None) |_hd, field_tys| {
12611261
for vec::each(fields) |f| {
12621262
let ix = ty::field_idx_strict(tcx, f.ident, field_tys);
12631263
let fldptr = GEPi(bcx, val, struct_field(ix));

src/rustc/middle/trans/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t,
547547
let mut cx = cx;
548548
match ty::get(t).sty {
549549
ty::ty_rec(*) | ty::ty_class(*) => {
550-
do expr::with_field_tys(cx.tcx(), t) |_has_dtor, field_tys| {
550+
do expr::with_field_tys(cx.tcx(), t, None) |_has_dtor, field_tys| {
551551
for vec::eachi(field_tys) |i, field_ty| {
552552
let llfld_a = GEPi(cx, av, struct_field(i));
553553
cx = f(cx, llfld_a, field_ty.mt.ty);

src/rustc/middle/trans/consts.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
162162
let bt = ty::expr_ty(cx.tcx, base);
163163
let bv = const_expr(cx, base);
164164
let (bt, bv) = const_autoderef(cx, bt, bv);
165-
do expr::with_field_tys(cx.tcx, bt) |_has_dtor, field_tys| {
165+
do expr::with_field_tys(cx.tcx, bt, None) |_has_dtor, field_tys| {
166166
let ix = ty::field_idx_strict(cx.tcx, field, field_tys);
167167

168168
// Note: ideally, we'd use `struct_field()` here instead
@@ -294,7 +294,9 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
294294
}
295295
ast::expr_struct(_, ref fs, _) => {
296296
let ety = ty::expr_ty(cx.tcx, e);
297-
let cs = do expr::with_field_tys(cx.tcx, ety) |_hd, field_tys| {
297+
let cs = do expr::with_field_tys(cx.tcx,
298+
ety,
299+
None) |_hd, field_tys| {
298300
field_tys.map(|field_ty| {
299301
match fs.find(|f| field_ty.ident == f.node.ident) {
300302
Some(f) => const_expr(cx, f.node.expr),

src/rustc/middle/trans/expr.rs

+68-3
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,12 @@ fn fn_data_to_datum(bcx: block,
850850
return bcx;
851851
}
852852

853-
fn with_field_tys<R>(tcx: ty::ctxt, ty: ty::t,
853+
// The optional node ID here is the node ID of the path identifying the enum
854+
// variant in use. If none, this cannot possibly an enum variant (so, if it
855+
// is and `node_id_opt` is none, this function fails).
856+
fn with_field_tys<R>(tcx: ty::ctxt,
857+
ty: ty::t,
858+
node_id_opt: Option<ast::node_id>,
854859
op: fn(bool, (&[ty::field])) -> R) -> R {
855860
match ty::get(ty).sty {
856861
ty::ty_rec(ref fields) => {
@@ -862,6 +867,30 @@ fn with_field_tys<R>(tcx: ty::ctxt, ty: ty::t,
862867
op(has_dtor, class_items_as_mutable_fields(tcx, did, substs))
863868
}
864869

870+
ty::ty_enum(_, ref substs) => {
871+
// We want the *variant* ID here, not the enum ID.
872+
match node_id_opt {
873+
None => {
874+
tcx.sess.bug(fmt!(
875+
"cannot get field types from the enum type %s \
876+
without a node ID",
877+
ty_to_str(tcx, ty)));
878+
}
879+
Some(node_id) => {
880+
match tcx.def_map.get(node_id) {
881+
ast::def_variant(_, variant_id) => {
882+
op(false, class_items_as_mutable_fields(
883+
tcx, variant_id, substs))
884+
}
885+
_ => {
886+
tcx.sess.bug(~"resolve didn't map this expr to a \
887+
variant ID")
888+
}
889+
}
890+
}
891+
}
892+
}
893+
865894
_ => {
866895
tcx.sess.bug(fmt!(
867896
"cannot get field types from the type %s",
@@ -877,7 +906,7 @@ fn trans_rec_field(bcx: block,
877906
let _icx = bcx.insn_ctxt("trans_rec_field");
878907

879908
let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
880-
do with_field_tys(bcx.tcx(), base_datum.ty) |_has_dtor, field_tys| {
909+
do with_field_tys(bcx.tcx(), base_datum.ty, None) |_dtor, field_tys| {
881910
let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys);
882911
DatumBlock {
883912
datum: base_datum.GEPi(bcx, [0u, 0u, ix], field_tys[ix].mt.ty),
@@ -969,9 +998,45 @@ fn trans_rec_or_struct(bcx: block,
969998
}
970999
}
9711000

1001+
// If this is a struct-like variant, write in the discriminant if
1002+
// necessary, position the address at the right location, and cast the
1003+
// address.
9721004
let ty = node_id_type(bcx, id);
9731005
let tcx = bcx.tcx();
974-
do with_field_tys(tcx, ty) |has_dtor, field_tys| {
1006+
let addr = match ty::get(ty).sty {
1007+
ty::ty_enum(_, ref substs) => {
1008+
match tcx.def_map.get(id) {
1009+
ast::def_variant(enum_id, variant_id) => {
1010+
let variant_info = ty::enum_variant_with_id(
1011+
tcx, enum_id, variant_id);
1012+
let addr = if ty::enum_is_univariant(tcx, enum_id) {
1013+
addr
1014+
} else {
1015+
Store(bcx,
1016+
C_int(bcx.ccx(), variant_info.disr_val),
1017+
GEPi(bcx, addr, [0, 0]));
1018+
GEPi(bcx, addr, [0, 1])
1019+
};
1020+
let fields = ty::class_items_as_mutable_fields(
1021+
tcx, variant_id, substs);
1022+
let field_lltys = do fields.map |field| {
1023+
type_of(bcx.ccx(),
1024+
ty::subst_tps(
1025+
tcx, substs.tps, None, field.mt.ty))
1026+
};
1027+
PointerCast(bcx, addr,
1028+
T_ptr(T_struct(~[T_struct(field_lltys)])))
1029+
}
1030+
_ => {
1031+
tcx.sess.bug(~"resolve didn't write the right def in for \
1032+
this struct-like variant")
1033+
}
1034+
}
1035+
}
1036+
_ => addr
1037+
};
1038+
1039+
do with_field_tys(tcx, ty, Some(id)) |has_dtor, field_tys| {
9751040
// evaluate each of the fields and store them into their
9761041
// correct locations
9771042
let mut temp_cleanups = ~[];

src/rustc/middle/ty.rs

+11
Original file line numberDiff line numberDiff line change
@@ -3721,6 +3721,17 @@ fn lookup_class_fields(cx: ctxt, did: ast::def_id) -> ~[field_ty] {
37213721
_ => cx.sess.bug(~"class ID bound to non-class")
37223722
}
37233723
}
3724+
Some(ast_map::node_variant(variant, _, _)) => {
3725+
match variant.node.kind {
3726+
ast::struct_variant_kind(struct_def) => {
3727+
class_field_tys(struct_def.fields)
3728+
}
3729+
_ => {
3730+
cx.sess.bug(~"struct ID bound to enum variant that isn't \
3731+
struct-like")
3732+
}
3733+
}
3734+
}
37243735
_ => {
37253736
cx.sess.bug(
37263737
fmt!("class ID not bound to an item: %s",

0 commit comments

Comments
 (0)