about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@gmail>2013-07-10 17:28:28 +0200
committerMichael Woerister <michaelwoerister@gmail>2013-07-19 07:57:38 +0200
commit12d87d39c1baebcce28ebff095bc811cd3d7402f (patch)
treeb26500e4a0040af990d324d362601e3217cad9fd
parent77a00cca0307ad4d7de084b45168387e8d82d92e (diff)
downloadrust-12d87d39c1baebcce28ebff095bc811cd3d7402f.tar.gz
rust-12d87d39c1baebcce28ebff095bc811cd3d7402f.zip
Cleanup of ty::VariantInfo and related functions.
-rw-r--r--src/librustc/metadata/csearch.rs2
-rw-r--r--src/librustc/metadata/decoder.rs6
-rw-r--r--src/librustc/middle/trans/base.rs4
-rw-r--r--src/librustc/middle/ty.rs144
-rw-r--r--src/librustc/middle/typeck/check/mod.rs119
5 files changed, 131 insertions, 144 deletions
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index f336b0f4e4c..2934751eeaf 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 e748ae89a9d..cf75bf45eaf 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 588b0b5c75f..a68a8437e1b 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<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;
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 9438d60a480..59d33fc086d 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<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);
-
-                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
-                         }
+                let mut discriminant = match last_discriminant {
+                    Some(val) => val + 1,
+                    None => INITIAL_DISCRIMINANT_VALUE
+                };
+
+                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) => {
-
-                        let fields : &[@struct_field] = struct_def.fields;
-
-                        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
-                        }
-                    }
-                }
+                    None => {}
+                };
+
+                let variant_info = @VariantInfo::from_ast_variant(cx, variant, discriminant);
+                last_discriminant = Some(discriminant);
+                variant_info
+
             }).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 0e1f8e617ff..319d94bae70 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);
-        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)));
+        let mut variants : ~[@ty::VariantInfo] = ~[];
+        let mut disr_vals: ~[int] = ~[];
+        let mut prev_disr_val : Option<int> = None;
 
-                  }
-                }
-            }
-            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);
+        for vs.iter().advance |v| {
 
-            let this_disr_val = *disr_val;
-            *disr_val += 1;
+            // 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
+            };
 
-            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))
-                }
+            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 => ()
             };
 
-            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
-            });
+            // 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);