Cleanup of ty::VariantInfo and related functions.

This commit is contained in:
Michael Woerister 2013-07-10 17:28:28 +02:00
parent 77a00cca03
commit 12d87d39c1
5 changed files with 129 additions and 142 deletions

View File

@ -90,7 +90,7 @@ pub fn maybe_get_item_ast(tcx: ty::ctxt, def: ast::def_id,
}
pub fn get_enum_variants(tcx: ty::ctxt, def: ast::def_id)
-> ~[ty::VariantInfo] {
-> ~[@ty::VariantInfo] {
let cstore = tcx.cstore;
let cdata = cstore::get_crate_data(cstore, def.crate);
return decoder::get_enum_variants(cstore.intr, cdata, def.node, tcx)

View File

@ -733,11 +733,11 @@ pub fn maybe_get_item_ast(cdata: cmd, tcx: ty::ctxt,
}
pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::node_id,
tcx: ty::ctxt) -> ~[ty::VariantInfo] {
tcx: ty::ctxt) -> ~[@ty::VariantInfo] {
let data = cdata.data;
let items = reader::get_doc(reader::Doc(data), tag_items);
let item = find_item(id, items);
let mut infos: ~[ty::VariantInfo] = ~[];
let mut infos: ~[@ty::VariantInfo] = ~[];
let variant_ids = enum_variant_ids(item, cdata);
let mut disr_val = 0;
for variant_ids.iter().advance |did| {
@ -753,7 +753,7 @@ pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::node_id,
Some(val) => { disr_val = val; }
_ => { /* empty */ }
}
infos.push(@ty::VariantInfo_{
infos.push(@ty::VariantInfo{
args: arg_tys,
arg_names: None,
ctor_ty: ctor_ty,

View File

@ -671,7 +671,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t,
let _icx = push_ctxt("iter_structural_ty");
fn iter_variant(cx: block, repr: &adt::Repr, av: ValueRef,
variant: ty::VariantInfo,
variant: @ty::VariantInfo,
tps: &[ty::t], f: val_and_ty_fn) -> block {
let _icx = push_ctxt("iter_variant");
let tcx = cx.tcx();
@ -2110,7 +2110,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
}
pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def,
id: ast::node_id, vi: @~[ty::VariantInfo],
id: ast::node_id, vi: @~[@ty::VariantInfo],
i: &mut uint) {
for enum_definition.variants.iter().advance |variant| {
let disr_val = vi[*i].disr_val;

View File

@ -50,6 +50,8 @@ use syntax::opt_vec;
use syntax::abi::AbiSet;
use syntax;
pub static INITIAL_DISCRIMINANT_VALUE: int = 0;
// Data types
#[deriving(Eq, IterBytes)]
@ -282,7 +284,7 @@ struct ctxt_ {
needs_unwind_cleanup_cache: @mut HashMap<t, bool>,
tc_cache: @mut HashMap<uint, TypeContents>,
ast_ty_to_ty_cache: @mut HashMap<node_id, ast_ty_to_ty_cache_entry>,
enum_var_cache: @mut HashMap<def_id, @~[VariantInfo]>,
enum_var_cache: @mut HashMap<def_id, @~[@VariantInfo]>,
ty_param_defs: @mut HashMap<ast::node_id, TypeParameterDef>,
adjustments: @mut HashMap<ast::node_id, @AutoAdjustment>,
normalized_cache: @mut HashMap<t, t>,
@ -3702,19 +3704,70 @@ pub struct VariantInfo_ {
vis: visibility
}
pub type VariantInfo = @VariantInfo_;
impl VariantInfo {
/// Creates a new VariantInfo from the corresponding ast representation.
///
/// Does not do any caching of the value in the type context.
pub fn from_ast_variant(cx: ctxt,
ast_variant: &ast::variant,
discriminant: int) -> VariantInfo {
let ctor_ty = node_id_to_type(cx, ast_variant.node.id);
match ast_variant.node.kind {
ast::tuple_variant_kind(ref args) => {
let arg_tys = if args.len() > 0 { ty_fn_args(ctor_ty).map(|a| *a) } else { ~[] };
return VariantInfo {
args: arg_tys,
arg_names: None,
ctor_ty: ctor_ty,
name: ast_variant.node.name,
id: ast_util::local_def(ast_variant.node.id),
disr_val: discriminant,
vis: ast_variant.node.vis
};
},
ast::struct_variant_kind(ref struct_def) => {
let fields : &[@struct_field] = struct_def.fields;
assert!(fields.len() > 0);
let arg_tys = ty_fn_args(ctor_ty).map(|a| *a);
let arg_names = do fields.map |field| {
match field.node.kind {
named_field(ident, _visibility) => ident,
unnamed_field => cx.sess.bug(
"enum_variants: all fields in struct must have a name")
}};
return VariantInfo {
args: arg_tys,
arg_names: Some(arg_names),
ctor_ty: ctor_ty,
name: ast_variant.node.name,
id: ast_util::local_def(ast_variant.node.id),
disr_val: discriminant,
vis: ast_variant.node.vis
};
}
}
}
}
pub fn substd_enum_variants(cx: ctxt,
id: ast::def_id,
substs: &substs)
-> ~[VariantInfo] {
-> ~[@VariantInfo] {
do enum_variants(cx, id).iter().transform |variant_info| {
let substd_args = variant_info.args.iter()
.transform(|aty| subst(cx, substs, *aty)).collect();
let substd_ctor_ty = subst(cx, substs, variant_info.ctor_ty);
@VariantInfo_ {
@VariantInfo {
args: substd_args,
ctor_ty: substd_ctor_ty,
..(**variant_info).clone()
@ -3832,7 +3885,7 @@ pub fn type_is_empty(cx: ctxt, t: t) -> bool {
}
}
pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] {
pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[@VariantInfo] {
match cx.enum_var_cache.find(&id) {
Some(&variants) => return variants,
_ => { /* fallthrough */ }
@ -3851,71 +3904,26 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] {
node: ast::item_enum(ref enum_definition, _),
_
}, _) => {
let mut disr_val = -1;
let mut last_discriminant : Option<int> = None;
@enum_definition.variants.iter().transform(|variant| {
let ctor_ty = node_id_to_type(cx, variant.node.id);
let mut discriminant = match last_discriminant {
Some(val) => val + 1,
None => INITIAL_DISCRIMINANT_VALUE
};
match variant.node.kind {
ast::tuple_variant_kind(ref args) => {
let arg_tys = if args.len() > 0u {
ty_fn_args(ctor_ty).map(|a| *a) }
else {
~[]
};
match variant.node.disr_expr {
Some (ex) => {
disr_val = match const_eval::eval_const_expr(cx,
ex) {
const_eval::const_int(val) => val as int,
_ => cx.sess.bug("enum_variants: bad disr expr")
}
}
_ => disr_val += 1
}
@VariantInfo_{
args: arg_tys,
arg_names: None,
ctor_ty: ctor_ty,
name: variant.node.name,
id: ast_util::local_def(variant.node.id),
disr_val: disr_val,
vis: variant.node.vis
}
match variant.node.disr_expr {
Some(e) => match const_eval::eval_const_expr_partial(cx, e) {
Ok(const_eval::const_int(val)) => { discriminant = val as int; }
_ => {}
},
ast::struct_variant_kind(struct_def) => {
None => {}
};
let fields : &[@struct_field] = struct_def.fields;
let variant_info = @VariantInfo::from_ast_variant(cx, variant, discriminant);
last_discriminant = Some(discriminant);
variant_info
let (arg_tys, arg_names) =
if fields.len() > 0 {
let arg_tys = ty_fn_args(ctor_ty).map(|a| *a);
let arg_names = do fields.map |field| { match field.node.kind {
named_field(ident, _visibility) => ident,
unnamed_field => cx.sess.bug(
"enum_variants: all fields in struct must have a name")
}};
(arg_tys, Some(arg_names))
} else {
(~[], None)
};
assert!(variant.node.disr_expr.is_none());
disr_val += 1;
@VariantInfo_{
args: arg_tys,
arg_names: arg_names,
ctor_ty: ctor_ty,
name: variant.node.name,
id: ast_util::local_def(variant.node.id),
disr_val: disr_val,
vis: variant.node.vis
}
}
}
}).collect()
}
_ => cx.sess.bug("enum_variants: id not bound to an enum")
@ -3930,7 +3938,7 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] {
pub fn enum_variant_with_id(cx: ctxt,
enum_id: ast::def_id,
variant_id: ast::def_id)
-> VariantInfo {
-> @VariantInfo {
let variants = enum_variants(cx, enum_id);
let mut i = 0;
while i < variants.len() {

View File

@ -81,7 +81,7 @@ use middle::const_eval;
use middle::pat_util::pat_id_map;
use middle::pat_util;
use middle::lint::unreachable_code;
use middle::ty::{FnSig, VariantInfo_};
use middle::ty::{FnSig, VariantInfo};
use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
use middle::ty::{substs, param_ty, ExprTyProvider};
use middle::ty;
@ -3133,87 +3133,66 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt,
vs: &[ast::variant],
id: ast::node_id) {
fn do_check(ccx: @mut CrateCtxt,
_sp: span,
vs: &[ast::variant],
id: ast::node_id,
disr_vals: &mut ~[int],
disr_val: &mut int,
variants: &mut ~[ty::VariantInfo]) {
id: ast::node_id)
-> ~[@ty::VariantInfo] {
let rty = ty::node_id_to_type(ccx.tcx, id);
let mut variants : ~[@ty::VariantInfo] = ~[];
let mut disr_vals: ~[int] = ~[];
let mut prev_disr_val : Option<int> = None;
for vs.iter().advance |v| {
for v.node.disr_expr.iter().advance |e_ref| {
let e = *e_ref;
debug!("disr expr, checking %s",
pprust::expr_to_str(e, ccx.tcx.sess.intr()));
let declty = ty::mk_int();
let fcx = blank_fn_ctxt(ccx, rty, e.id);
check_const_with_ty(fcx, e.span, e, declty);
// check_expr (from check_const pass) doesn't guarantee
// that the expression is in an form that eval_const_expr can
// handle, so we may still get an internal compiler error
match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
Ok(const_eval::const_int(val)) => {
*disr_val = val as int;
}
Ok(_) => {
ccx.tcx.sess.span_err(e.span, "expected signed integer \
constant");
}
Err(ref err) => {
ccx.tcx.sess.span_err(e.span,
fmt!("expected constant: %s", (*err)));
}
}
}
if disr_vals.contains(&*disr_val) {
ccx.tcx.sess.span_err(v.span,
"discriminator value already exists");
}
disr_vals.push(*disr_val);
let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id);
let this_disr_val = *disr_val;
*disr_val += 1;
let (arg_tys, arg_names) = match v.node.kind {
ast::tuple_variant_kind(ref args) if args.len() > 0u => {
(ty::ty_fn_args(ctor_ty).map(|a| *a), None)
}
ast::tuple_variant_kind(_) => {
(~[], None)
}
ast::struct_variant_kind(struct_def) => {
let tys = ty::ty_fn_args(ctor_ty).map(|a| *a);
let names = do struct_def.fields.map |field| { match field.node.kind {
ast::named_field(ident, _visibility) => ident,
ast::unnamed_field => ccx.tcx.sess.bug(
"enum_variants: all fields in struct must have a name")
}};
(tys, Some(names))
}
// If the discriminant value is specified explicitly in the enum check whether the
// initialization expression is valid, otherwise use the last value plus one.
let mut current_disr_val = match prev_disr_val {
Some(prev_disr_val) => prev_disr_val + 1,
None => ty::INITIAL_DISCRIMINANT_VALUE
};
variants.push(@VariantInfo_{
args: arg_tys,
arg_names: arg_names,
ctor_ty: ctor_ty,
name: v.node.name,
id: local_def(v.node.id),
disr_val: this_disr_val,
vis: v.node.vis
});
match v.node.disr_expr {
Some(e) => {
debug!("disr expr, checking %s", pprust::expr_to_str(e, ccx.tcx.sess.intr()));
let declty = ty::mk_int();
let fcx = blank_fn_ctxt(ccx, rty, e.id);
check_const_with_ty(fcx, e.span, e, declty);
// check_expr (from check_const pass) doesn't guarantee
// that the expression is in an form that eval_const_expr can
// handle, so we may still get an internal compiler error
match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
Ok(const_eval::const_int(val)) => { current_disr_val = val as int; }
Ok(_) => {
ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
}
Err(ref err) => {
ccx.tcx.sess.span_err(e.span, fmt!("expected constant: %s", (*err)));
}
}
},
None => ()
};
// Check for duplicate discriminator values
if disr_vals.contains(&current_disr_val) {
ccx.tcx.sess.span_err(v.span, "discriminator value already exists");
}
disr_vals.push(current_disr_val);
let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val);
prev_disr_val = Some(current_disr_val);
variants.push(variant_info);
}
return variants;
}
let rty = ty::node_id_to_type(ccx.tcx, id);
let mut disr_vals: ~[int] = ~[];
let mut disr_val = 0;
let mut variants = ~[];
do_check(ccx, sp, vs, id, &mut disr_vals, &mut disr_val, &mut variants);
let variants = do_check(ccx, vs, id);
// cache so that ty::enum_variants won't repeat this work
ccx.tcx.enum_var_cache.insert(local_def(id), @variants);