From 12d87d39c1baebcce28ebff095bc811cd3d7402f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 10 Jul 2013 17:28:28 +0200 Subject: [PATCH] Cleanup of ty::VariantInfo and related functions. --- src/librustc/metadata/csearch.rs | 2 +- src/librustc/metadata/decoder.rs | 6 +- src/librustc/middle/trans/base.rs | 4 +- src/librustc/middle/ty.rs | 138 +++++++++++++----------- src/librustc/middle/typeck/check/mod.rs | 121 +++++++++------------ 5 files changed, 129 insertions(+), 142 deletions(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index f336b0f4e4c5..2934751eeafd 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -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) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index e748ae89a9dc..cf75bf45eaf0 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -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, diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 588b0b5c75f4..a68a8437e1bb 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -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( } 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; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9438d60a4800..59d33fc086dd 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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, tc_cache: @mut HashMap, ast_ty_to_ty_cache: @mut HashMap, - enum_var_cache: @mut HashMap, + enum_var_cache: @mut HashMap, ty_param_defs: @mut HashMap, adjustments: @mut HashMap, normalized_cache: @mut HashMap, @@ -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 = 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() { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 0e1f8e617ff7..319d94bae703 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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 = 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(¤t_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);