summary refs log tree commit diff
path: root/src/comp/metadata
diff options
context:
space:
mode:
authorKevin Atkinson <kevina@cs.utah.edu>2012-01-10 14:50:40 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-01-10 15:59:57 -0800
commit08abf8d37fa549ebc67f80d80530f4aa43d716e4 (patch)
treef6c9bce62c494a37d989d07be4661f57c0c7eba3 /src/comp/metadata
parentd0fe6723fc2f431205092bda9ec399d932081bd0 (diff)
downloadrust-08abf8d37fa549ebc67f80d80530f4aa43d716e4.tar.gz
rust-08abf8d37fa549ebc67f80d80530f4aa43d716e4.zip
Support explicit discriminant numbers on tag variants.
Addresses issue #1393.

For now disallow disr. values unless all variants use nullary
contractors (i.e. "enum-like").

Disr. values are now encoded in the crate metadata, but only when it
will differ from the inferred value based on the order.
Diffstat (limited to 'src/comp/metadata')
-rw-r--r--src/comp/metadata/common.rs3
-rw-r--r--src/comp/metadata/decoder.rs20
-rw-r--r--src/comp/metadata/encoder.rs12
3 files changed, 34 insertions, 1 deletions
diff --git a/src/comp/metadata/common.rs b/src/comp/metadata/common.rs
index db415d5d31a..e1c05bf2c9f 100644
--- a/src/comp/metadata/common.rs
+++ b/src/comp/metadata/common.rs
@@ -70,6 +70,9 @@ const tag_item_method: uint = 0x31u;
 const tag_impl_iface: uint = 0x32u;
 const tag_impl_iface_did: uint = 0x33u;
 
+// discriminator value for variants
+const tag_disr_val: uint = 0x34u;
+
 // djb's cdb hashes.
 fn hash_node_id(&&node_id: int) -> uint { ret 177573u ^ (node_id as uint); }
 
diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs
index a253e116fe8..c40e459bb5c 100644
--- a/src/comp/metadata/decoder.rs
+++ b/src/comp/metadata/decoder.rs
@@ -88,6 +88,17 @@ fn variant_tag_id(d: ebml::doc) -> ast::def_id {
     ret parse_def_id(ebml::doc_data(tagdoc));
 }
 
+fn variant_disr_val(d: ebml::doc) -> option::t<int> {
+    alt ebml::maybe_get_doc(d, tag_disr_val) {
+      some(val_doc) {
+        let val_buf = ebml::doc_data(val_doc);
+        let val = int::parse_buf(val_buf, 10u);
+        ret some(val);
+      }
+      _ { ret none;}
+    }
+}
+
 fn doc_type(doc: ebml::doc, tcx: ty::ctxt, cdata: cmd) -> ty::t {
     let tp = ebml::get_doc(doc, tag_items_data_item_type);
     parse_ty_data(tp.data, cdata.cnum, tp.start, tcx, {|did|
@@ -240,6 +251,7 @@ fn get_tag_variants(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
     let item = find_item(id, items);
     let infos: [ty::variant_info] = [];
     let variant_ids = tag_variant_ids(item, cdata);
+    let disr_val = 0;
     for did: ast::def_id in variant_ids {
         let item = find_item(did.node, items);
         let ctor_ty = item_type(item, tcx, cdata);
@@ -250,7 +262,13 @@ fn get_tag_variants(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
           }
           _ { /* Nullary tag variant. */ }
         }
-        infos += [@{args: arg_tys, ctor_ty: ctor_ty, id: did}];
+        alt variant_disr_val(item) {
+          some(val) { disr_val = val; }
+          _         { /* empty */ }
+        }
+        infos += [@{args: arg_tys, ctor_ty: ctor_ty, id: did,
+                    disr_val: disr_val}];
+        disr_val += 1;
     }
     ret infos;
 }
diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs
index de1f9eacbcb..e666d204020 100644
--- a/src/comp/metadata/encoder.rs
+++ b/src/comp/metadata/encoder.rs
@@ -228,6 +228,12 @@ fn encode_discriminant(ecx: @encode_ctxt, ebml_w: ebml::writer, id: node_id) {
     ebml::end_tag(ebml_w);
 }
 
+fn encode_disr_val(_ecx: @encode_ctxt, ebml_w: ebml::writer, disr_val: int) {
+    ebml::start_tag(ebml_w, tag_disr_val);
+    ebml_w.writer.write(str::bytes(int::to_str(disr_val,10u)));
+    ebml::end_tag(ebml_w);
+}
+
 fn encode_tag_id(ebml_w: ebml::writer, id: def_id) {
     ebml::start_tag(ebml_w, tag_items_data_item_tag_id);
     ebml_w.writer.write(str::bytes(def_to_str(id)));
@@ -237,6 +243,7 @@ fn encode_tag_id(ebml_w: ebml::writer, id: def_id) {
 fn encode_tag_variant_info(ecx: @encode_ctxt, ebml_w: ebml::writer,
                            id: node_id, variants: [variant],
                            &index: [entry<int>], ty_params: [ty_param]) {
+    let disr_val = 0;
     for variant: variant in variants {
         index += [{val: variant.node.id, pos: ebml_w.writer.tell()}];
         ebml::start_tag(ebml_w, tag_items_data_item);
@@ -249,8 +256,13 @@ fn encode_tag_variant_info(ecx: @encode_ctxt, ebml_w: ebml::writer,
             encode_symbol(ecx, ebml_w, variant.node.id);
         }
         encode_discriminant(ecx, ebml_w, variant.node.id);
+        if variant.node.disr_val != disr_val {
+            encode_disr_val(ecx, ebml_w, variant.node.disr_val);
+            disr_val = variant.node.disr_val;
+        }
         encode_type_param_bounds(ebml_w, ecx, ty_params);
         ebml::end_tag(ebml_w);
+        disr_val += 1;
     }
 }