about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-04-26 12:15:46 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-05-02 13:38:56 -0700
commit3d4ef74c9bdd2179199c02d7cbe58266c849b057 (patch)
treefd383163df55f42913b91a701b9c93acb89cdbb0 /src/rustc
parent8d9f67003a4def3894096e7971cde49e638ac449 (diff)
downloadrust-3d4ef74c9bdd2179199c02d7cbe58266c849b057.tar.gz
rust-3d4ef74c9bdd2179199c02d7cbe58266c849b057.zip
Encode the ifaces a class implements in metadata
This lets you use class A as if it had type B if A implements B,
and A and B are in different crates from your own.

Closes #2285
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/metadata/common.rs13
-rw-r--r--src/rustc/metadata/decoder.rs43
-rw-r--r--src/rustc/metadata/encoder.rs91
-rw-r--r--src/rustc/metadata/tydecode.rs10
-rw-r--r--src/rustc/middle/resolve.rs10
-rw-r--r--src/rustc/middle/typeck.rs4
6 files changed, 129 insertions, 42 deletions
diff --git a/src/rustc/metadata/common.rs b/src/rustc/metadata/common.rs
index 4262266a0d9..54a05cc206d 100644
--- a/src/rustc/metadata/common.rs
+++ b/src/rustc/metadata/common.rs
@@ -70,7 +70,7 @@ const tag_crate_dep_vers: uint = 0x2cu;
 
 const tag_mod_impl: uint = 0x30u;
 
-const tag_item_method: uint = 0x31u;
+const tag_item_iface_method: uint = 0x31u;
 const tag_impl_iface: uint = 0x32u;
 
 // discriminator value for variants
@@ -85,6 +85,17 @@ const tag_item_field: uint = 0x44u;
 const tag_class_mut: uint = 0x45u;
 
 const tag_region_param: uint = 0x46u;
+const tag_mod_impl_use: uint = 0x47u;
+const tag_mod_impl_iface: uint = 0x48u;
+/*
+  iface items contain tag_item_iface_method elements,
+  impl items contain tag_item_impl_method elements, and classes
+  have both. That's because some code treats classes like ifaces,
+  and other code treats them like impls. Because classes can contain
+  both, tag_item_iface_method and tag_item_impl_method have to be two
+  different tags.
+ */
+const tag_item_impl_method: uint = 0x49u;
 
 // used to encode crate_ctxt side tables
 enum astencode_tag { // Reserves 0x50 -- 0x6f
diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs
index 50a1093153b..ef0bd869482 100644
--- a/src/rustc/metadata/decoder.rs
+++ b/src/rustc/metadata/decoder.rs
@@ -156,8 +156,7 @@ fn item_impl_iface(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
     -> option<ty::t> {
     let mut result = none;
     ebml::tagged_docs(item, tag_impl_iface) {|ity|
-        result = some(parse_ty_data(ity.data, cdata.cnum, ity.start, tcx,
-                             {|did| translate_def_id(cdata, did)}));
+        result = some(doc_type(ity, tcx, cdata));
     };
     result
 }
@@ -304,7 +303,7 @@ fn get_impl_iface(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
 fn get_impl_method(cdata: cmd, id: ast::node_id, name: str) -> ast::def_id {
     let items = ebml::get_doc(ebml::doc(cdata.data), tag_items);
     let mut found = none;
-    ebml::tagged_docs(find_item(id, items), tag_item_method) {|mid|
+    ebml::tagged_docs(find_item(id, items), tag_item_impl_method) {|mid|
         let m_did = parse_def_id(ebml::doc_data(mid));
         if item_name(find_item(m_did.node, items)) == name {
             found = some(translate_def_id(cdata, m_did));
@@ -320,7 +319,7 @@ fn get_class_method(cdata: cmd, id: ast::node_id, name: str) -> ast::def_id {
             some(it) { it }
             none { fail (#fmt("get_class_method: class id not found \
              when looking up method %s", name)) }};
-    ebml::tagged_docs(cls_items, tag_item_method) {|mid|
+    ebml::tagged_docs(cls_items, tag_item_iface_method) {|mid|
         let m_did = class_member_id(mid, cdata);
         if item_name(mid) == name {
             found = some(m_did);
@@ -398,10 +397,12 @@ fn get_enum_variants(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
 fn item_impl_methods(cdata: cmd, item: ebml::doc, base_tps: uint)
     -> [@middle::resolve::method_info] {
     let mut rslt = [];
-    ebml::tagged_docs(item, tag_item_method) {|doc|
+    ebml::tagged_docs(item, tag_item_impl_method) {|doc|
         let m_did = parse_def_id(ebml::doc_data(doc));
         let mth_item = lookup_item(m_did.node, cdata.data);
         rslt += [@{did: translate_def_id(cdata, m_did),
+                    /* FIXME tjc: take a look at this, it may relate
+                     to #2323 */
                    n_tps: item_ty_param_count(mth_item) - base_tps,
                    ident: item_name(mth_item)}];
     }
@@ -416,21 +417,39 @@ fn get_impls_for_mod(cdata: cmd, m_id: ast::node_id,
     let mod_item = lookup_item(m_id, data);
     let mut result = [];
     ebml::tagged_docs(mod_item, tag_mod_impl) {|doc|
-        let did = parse_def_id(ebml::doc_data(doc));
+        /*
+          Pair of an item did and an iface did.
+          The second one is unneeded if the first id names
+          an impl; disambiguates if it's a class
+        */
+        let did = parse_def_id(ebml::doc_data(ebml::get_doc(doc,
+                                                      tag_mod_impl_use)));
         let local_did = translate_def_id(cdata, did);
-        // The impl may be defined in a different crate. Ask the caller
-        // to give us the metadata
+        /*
+        // iface is optional
+        let iface_did = option::map(ebml::maybe_get_doc(doc,
+                                           tag_mod_impl_iface)) {|d|
+                                     parse_def_id(ebml::doc_data(d))};
+        option::iter(iface_did) {|x|
+                let _local_iface_did = translate_def_id(cdata, x);
+        };
+        */
+        // CONFUSED -- previous code is pointless
+          // The impl may be defined in a different crate. Ask the caller
+          // to give us the metadata
         let impl_cdata = get_cdata(local_did.crate);
         let impl_data = impl_cdata.data;
         let item = lookup_item(local_did.node, impl_data);
         let nm = item_name(item);
         if alt name { some(n) { n == nm } none { true } } {
-            let base_tps = item_ty_param_count(item);
-            result += [@{
+           let base_tps = item_ty_param_count(item);
+           result += [@{
+                   // here, we need to... reconstruct the iface_ref?
+                   // probz broken
                 did: local_did, ident: nm,
                 methods: item_impl_methods(impl_cdata, item, base_tps)
             }];
-        }
+        };
     }
     @result
 }
@@ -441,7 +460,7 @@ fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
     let data = cdata.data;
     let item = lookup_item(id, data);
     let mut result = [];
-    ebml::tagged_docs(item, tag_item_method) {|mth|
+    ebml::tagged_docs(item, tag_item_iface_method) {|mth|
         let bounds = item_ty_param_bounds(mth, tcx, cdata);
         let name = item_name(mth);
         let ty = doc_type(mth, tcx, cdata);
diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs
index a1c996dccf1..9fd63ecf2fd 100644
--- a/src/rustc/metadata/encoder.rs
+++ b/src/rustc/metadata/encoder.rs
@@ -1,5 +1,7 @@
 // Metadata encoding
 
+import util::ppaux::ty_to_str;
+
 import std::{ebml, map, list};
 import std::map::hashmap;
 import io::writer_util;
@@ -197,6 +199,12 @@ fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt,
     }
 }
 
+fn encode_iface_ref(ebml_w: ebml::writer, ecx: @encode_ctxt, t: @iface_ref) {
+    ebml_w.start_tag(tag_impl_iface);
+    encode_type(ecx, ebml_w, node_id_to_type(ecx.ccx.tcx, t.id));
+    ebml_w.end_tag();
+}
+
 fn encode_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt, crate: @crate)
     -> [entry<str>] {
     let mut index: [entry<str>] = [];
@@ -361,12 +369,52 @@ fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::writer, md: _mod,
       list::cons(impls, @list::nil) {
         for vec::each(*impls) {|i|
             if ast_util::is_exported(i.ident, md) {
-                ebml_w.wr_tagged_str(tag_mod_impl, def_to_str(i.did));
-            }
-        }
+                ebml_w.start_tag(tag_mod_impl);
+            /* If did stands for an iface
+               ref, we need to map it to its parent class */
+                ebml_w.start_tag(tag_mod_impl_use);
+                let iface_ty = alt ecx.ccx.tcx.items.get(i.did.node) {
+                  ast_map::node_item(it@@{node: cl@item_class(*),_},_) {
+                    ebml_w.wr_str(def_to_str(local_def(it.id)));
+                    some(ty::lookup_item_type(ecx.ccx.tcx, i.did).ty)
+                  }
+                  ast_map::node_item(@{node: item_impl(_,_,
+                                           some(ifce),_,_),_},_) {
+                    ebml_w.wr_str(def_to_str(i.did));
+                    some(ty::node_id_to_type(ecx.ccx.tcx, ifce.id))
+                  }
+                  _ {
+                      ebml_w.wr_str(def_to_str(i.did)); none
+                  }
+                };
+                ebml_w.end_tag();
+
+                /*
+                /* Write the iface did if it exists */
+                option::iter(iface_ty) {|i|
+                alt ty::get(i).struct {
+                  ty::ty_iface(did, tys) {
+                    // FIXME: tys?
+                      ebml_w.start_tag(tag_mod_impl_iface);
+                     ebml_w.wr_str(def_to_str(did));
+                     ebml_w.end_tag();
+
+                  }
+                  t {
+                      ecx.ccx.tcx.sess.bug(#fmt("Expected item to implement \
+                       an iface, but found %s",
+                       util::ppaux::ty_to_str(ecx.ccx.tcx, i)));
+                  }
+                }}
+                */
+                ebml_w.end_tag();
+            } // if
+            } // for
+      } // list::cons alt
+      _ {
+          ecx.ccx.tcx.sess.bug(#fmt("encode_info_for_mod: empty impl_map \
+            entry for %?", path));
       }
-      _ { ecx.ccx.tcx.sess.bug(#fmt("encode_info_for_mod: empty impl_map \
-            entry for %?", path)); }
     }
     encode_path(ebml_w, path, ast_map::path_mod(name));
     ebml_w.end_tag();
@@ -571,7 +619,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
         encode_enum_variant_info(ecx, ebml_w, item.id, variants,
                                  path, index, tps);
       }
-      item_class(tps, _ifaces, items, ctor, rp) {
+      item_class(tps, ifaces, items, ctor, rp) {
         /* First, encode the fields and methods
            These come first because we need to write them to make
            the index, and the index needs to be in the item for the
@@ -589,7 +637,9 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
         encode_name(ebml_w, item.ident);
         encode_path(ebml_w, path, ast_map::path_name(item.ident));
         encode_region_param(ebml_w, rp);
-        /* FIXME: encode ifaces */
+        for ifaces.each {|t|
+           encode_iface_ref(ebml_w, ecx, t);
+        }
         /* Encode def_ids for each field and method
          for methods, write all the stuff get_iface_method
         needs to know*/
@@ -605,14 +655,21 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
            alt m.privacy {
               priv { /* do nothing */ }
               pub {
-                ebml_w.start_tag(tag_item_method);
-                #debug("Writing %s %d", m.ident, m.id);
+                /* Write the info that's needed when viewing this class
+                   as an iface */
+                ebml_w.start_tag(tag_item_iface_method);
                 encode_family(ebml_w, purity_fn_family(m.decl.purity));
                 encode_name(ebml_w, m.ident);
                 encode_type_param_bounds(ebml_w, ecx, tps + m.tps);
                 encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id));
                 encode_def_id(ebml_w, local_def(m.id));
                 ebml_w.end_tag();
+                /* Write the info that's needed when viewing this class
+                   as an impl (just the method def_id) */
+                ebml_w.start_tag(tag_item_impl_method);
+                ebml_w.writer.write(str::bytes(def_to_str(local_def(m.id))));
+                ebml_w.end_tag();
+
               }
            }
         }
@@ -659,19 +716,13 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
         encode_name(ebml_w, item.ident);
         for methods.each {|m|
-            ebml_w.start_tag(tag_item_method);
+            ebml_w.start_tag(tag_item_impl_method);
             ebml_w.writer.write(str::bytes(def_to_str(local_def(m.id))));
             ebml_w.end_tag();
         }
-        alt ifce {
-          some(t) {
-            let i_ty = ty::node_id_to_type(tcx, t.id);
-            ebml_w.start_tag(tag_impl_iface);
-            write_type(ecx, ebml_w, i_ty);
-            ebml_w.end_tag();
-          }
-          _ {}
-        }
+        option::iter(ifce) {|t|
+           encode_iface_ref(ebml_w, ecx, t)
+        };
         encode_path(ebml_w, path, ast_map::path_name(item.ident));
         ebml_w.end_tag();
 
@@ -693,7 +744,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
         encode_name(ebml_w, item.ident);
         let mut i = 0u;
         for vec::each(*ty::iface_methods(tcx, local_def(item.id))) {|mty|
-            ebml_w.start_tag(tag_item_method);
+            ebml_w.start_tag(tag_item_iface_method);
             encode_name(ebml_w, mty.ident);
             encode_type_param_bounds(ebml_w, ecx, ms[i].tps);
             encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty));
diff --git a/src/rustc/metadata/tydecode.rs b/src/rustc/metadata/tydecode.rs
index 46c39256938..7f627e39039 100644
--- a/src/rustc/metadata/tydecode.rs
+++ b/src/rustc/metadata/tydecode.rs
@@ -481,15 +481,13 @@ fn parse_def_id(buf: [u8]) -> ast::def_id {
 
     let crate_num = alt uint::parse_buf(crate_part, 10u) {
        some(cn) { cn as int }
-       none { fail (#fmt("internal error: parse_def_id: error parsing %? \
-                         as crate",
-                         crate_part)); }
+       none { fail (#fmt("internal error: parse_def_id: crate number \
+         expected, but found %?", crate_part)); }
     };
     let def_num = alt uint::parse_buf(def_part, 10u) {
        some(dn) { dn as int }
-       none { fail (#fmt("internal error: parse_def_id: error parsing %? \
-                         as id",
-                         def_part)); }
+       none { fail (#fmt("internal error: parse_def_id: id expected, but \
+         found %?", def_part)); }
     };
     ret {crate: crate_num, node: def_num};
 }
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index 3e380816dfd..cd0696c4104 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -2115,8 +2115,14 @@ fn check_exports(e: @env) {
 // Impl resolution
 
 type method_info = {did: def_id, n_tps: uint, ident: ast::ident};
-/* what are the did and ident here? */
-/* ident = the name of the impl */
+/* An _impl represents an implementation that's currently in scope.
+   Its fields:
+   * did: the def id of the class or impl item
+   * ident: the name of the impl, unless it has no name (as in
+   "impl of X") in which case the ident
+   is the ident of the iface that's being implemented
+   * methods: the item's methods
+*/
 type _impl = {did: def_id, ident: ast::ident, methods: [@method_info]};
 type iscopes = list<@[@_impl]>;
 
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 931d3d9e790..944d04ee402 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -4686,8 +4686,10 @@ mod vtable {
             let mut found = [];
 
             for list::each(isc) {|impls|
+            /* For each impl in scope... */
                 for vec::each(*impls) {|im|
-                    // find the iface that the impl is an impl of (if any)
+                    // im = one specific impl
+                    // find the iface that im implements (if any)
                     let of_ty = alt ty::impl_iface(tcx, im.did) {
                       some(of_ty) { of_ty }
                       _ { cont; }