about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-04-10 10:52:06 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-04-10 11:01:36 -0700
commitfd26743bedbd10f4c1cad7aecff50de6282d32dd (patch)
tree3ce0e7a34633a86f91f177ae84683232fcf971de
parentb2ec26c15283def5d5d8bcdd74bfdd84e918c46e (diff)
downloadrust-fd26743bedbd10f4c1cad7aecff50de6282d32dd.tar.gz
rust-fd26743bedbd10f4c1cad7aecff50de6282d32dd.zip
Generic classes and generic class methods work cross-crate
Classes can have ty params now. So can methods inside classes.
That was probably true before, but now it should still work if you
call methods in a class that's defined in a different crate. Yay!
-rw-r--r--src/librustsyntax/ast.rs3
-rw-r--r--src/librustsyntax/ast_util.rs5
-rw-r--r--src/librustsyntax/fold.rs6
-rw-r--r--src/librustsyntax/visit.rs21
-rw-r--r--src/rustc/metadata/astencode.rs29
-rw-r--r--src/rustc/metadata/encoder.rs26
-rw-r--r--src/rustc/middle/ast_map.rs29
-rw-r--r--src/rustc/middle/mutbl.rs18
-rw-r--r--src/rustc/middle/resolve.rs2
-rw-r--r--src/rustc/middle/trans/base.rs51
-rw-r--r--src/rustc/middle/trans/common.rs4
-rw-r--r--src/rustc/middle/trans/debuginfo.rs15
-rw-r--r--src/rustc/middle/trans/type_use.rs11
-rw-r--r--src/rustc/middle/tstate/ck.rs2
-rw-r--r--src/rustc/middle/ty.rs10
-rw-r--r--src/rustc/middle/typeck.rs28
-rw-r--r--src/test/auxiliary/cci_class_6.rs21
-rw-r--r--src/test/run-pass/class-poly-methods-cross-crate.rs15
-rw-r--r--src/test/run-pass/class-poly-methods.rs2
19 files changed, 216 insertions, 82 deletions
diff --git a/src/librustsyntax/ast.rs b/src/librustsyntax/ast.rs
index b2e0583c61b..44a37066a56 100644
--- a/src/librustsyntax/ast.rs
+++ b/src/librustsyntax/ast.rs
@@ -643,7 +643,7 @@ enum item_ {
     item_native_mod(native_mod),
     item_ty(@ty, [ty_param]),
     item_enum([variant], [ty_param]),
-    item_res(fn_decl /* dtor */, [ty_param], blk,
+    item_res(fn_decl /* dtor */, [ty_param], blk /* dtor body */,
              node_id /* dtor id */, node_id /* ctor id */),
     item_class([ty_param], /* ty params for class */
                [@class_member], /* methods, etc. */
@@ -703,6 +703,7 @@ enum inlined_item {
     ii_item(@item),
     ii_method(def_id /* impl id */, @method),
     ii_native(@native_item),
+    ii_ctor(class_ctor, ident, [ty_param], def_id /* parent id */)
 }
 
 //
diff --git a/src/librustsyntax/ast_util.rs b/src/librustsyntax/ast_util.rs
index 63c46b63341..f81f09b2c52 100644
--- a/src/librustsyntax/ast_util.rs
+++ b/src/librustsyntax/ast_util.rs
@@ -302,6 +302,7 @@ impl inlined_item_methods for inlined_item {
           ii_item(i) { i.ident }
           ii_native(i) { i.ident }
           ii_method(_, m) { m.ident }
+          ii_ctor(_, nm, _, _) { nm }
         }
     }
 
@@ -310,6 +311,7 @@ impl inlined_item_methods for inlined_item {
           ii_item(i) { i.id }
           ii_native(i) { i.id }
           ii_method(_, m) { m.id }
+          ii_ctor(ctor, _, _, _) { ctor.node.id }
         }
     }
 
@@ -318,6 +320,9 @@ impl inlined_item_methods for inlined_item {
           ii_item(i) { v.visit_item(i, e, v) }
           ii_native(i) { v.visit_native_item(i, e, v) }
           ii_method(_, m) { visit::visit_method_helper(m, e, v) }
+          ii_ctor(ctor, nm, tps, parent_id) {
+              visit::visit_class_ctor_helper(ctor, nm, tps, parent_id, e, v);
+          }
         }
     }
 }
diff --git a/src/librustsyntax/fold.rs b/src/librustsyntax/fold.rs
index 07411a3051d..ec6d871472b 100644
--- a/src/librustsyntax/fold.rs
+++ b/src/librustsyntax/fold.rs
@@ -14,6 +14,8 @@ export noop_fold_ty;
 export noop_fold_block;
 export wrap;
 export fold_ty_param;
+export fold_ty_params;
+export fold_fn_decl;
 
 type ast_fold = @mut a_f;
 
@@ -270,10 +272,12 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
           item_class(typms, items, ctor) {
               let ctor_body = fld.fold_block(ctor.node.body);
               let ctor_decl = fold_fn_decl(ctor.node.dec, fld);
+              let ctor_id   = fld.new_id(ctor.node.id);
               item_class(typms,
                          vec::map(items, fld.fold_class_item),
                          {node: {body: ctor_body,
-                                     dec: ctor_decl with ctor.node}
+                                 dec: ctor_decl,
+                                 id: ctor_id with ctor.node}
                              with ctor})
           }
           item_impl(tps, ifce, ty, methods) {
diff --git a/src/librustsyntax/visit.rs b/src/librustsyntax/visit.rs
index 6250c9dc7c9..b4ffce0730d 100644
--- a/src/librustsyntax/visit.rs
+++ b/src/librustsyntax/visit.rs
@@ -18,13 +18,14 @@ enum fn_kind {
     fk_res(ident, [ty_param]),
     fk_anon(proto),  //< an anonymous function like fn@(...)
     fk_fn_block,     //< a block {||...}
-    fk_ctor(ident, [ty_param]) // class constructor
+    fk_ctor(ident, [ty_param], node_id /* self id */,
+            def_id /* parent class id */) // class constructor
 }
 
 fn name_of_fn(fk: fn_kind) -> ident {
     alt fk {
       fk_item_fn(name, _) | fk_method(name, _, _) | fk_res(name, _)
-          | fk_ctor(name, _) { name }
+          | fk_ctor(name, _, _, _) { name }
       fk_anon(_) | fk_fn_block { "anon" }
     }
 }
@@ -32,7 +33,7 @@ fn name_of_fn(fk: fn_kind) -> ident {
 fn tps_of_fn(fk: fn_kind) -> [ty_param] {
     alt fk {
       fk_item_fn(_, tps) | fk_method(_, tps, _) | fk_res(_, tps)
-          | fk_ctor(_, tps) { tps }
+          | fk_ctor(_, tps, _, _) { tps }
       fk_anon(_) | fk_fn_block { [] }
     }
 }
@@ -141,9 +142,8 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
           for members.each {|m|
              v.visit_class_item(m, e, v);
           }
-          // make up a fake fn so as to call visit_fn on the ctor
-          v.visit_fn(fk_ctor(i.ident, tps), ctor.node.dec,
-                     ctor.node.body, ctor.span, ctor.node.id, e, v);
+          visit_class_ctor_helper(ctor, i.ident, tps,
+                                  ast_util::local_def(i.id), e, v);
       }
       item_iface(tps, methods) {
         v.visit_ty_params(tps, e, v);
@@ -270,6 +270,15 @@ fn visit_method_helper<E>(m: @method, e: E, v: vt<E>) {
                m.id, e, v);
 }
 
+// Similar logic to the comment on visit_method_helper - Tim
+fn visit_class_ctor_helper<E>(ctor: class_ctor, nm: ident, tps: [ty_param],
+                              parent_id: def_id, e: E, v: vt<E>) {
+    v.visit_fn(visit::fk_ctor(nm, tps, ctor.node.self_id,
+                              parent_id), ctor.node.dec,
+               ctor.node.body, ctor.span, ctor.node.id, e, v)
+
+}
+
 fn visit_fn<E>(fk: fn_kind, decl: fn_decl, body: blk, _sp: span,
                _id: node_id, e: E, v: vt<E>) {
     visit_fn_decl(decl, e, v);
diff --git a/src/rustc/metadata/astencode.rs b/src/rustc/metadata/astencode.rs
index b2aa4fe312f..1b007b348af 100644
--- a/src/rustc/metadata/astencode.rs
+++ b/src/rustc/metadata/astencode.rs
@@ -1,3 +1,5 @@
+import util::ppaux::ty_to_str;
+
 import syntax::ast;
 import syntax::fold;
 import syntax::visit;
@@ -200,8 +202,14 @@ fn visit_ids(item: ast::inlined_item, vfn: fn@(ast::node_id)) {
             vfn(id);
 
             alt fk {
+              visit::fk_ctor(nm, tps, self_id, parent_id) {
+                vec::iter(tps) {|tp| vfn(tp.id)}
+                vfn(id);
+                vfn(self_id);
+                vfn(parent_id.node);
+              }
               visit::fk_item_fn(_, tps) |
-              visit::fk_res(_, tps) | visit::fk_ctor(_, tps) {
+              visit::fk_res(_, tps) {
                 vec::iter(tps) {|tp| vfn(tp.id)}
               }
               visit::fk_method(_, tps, m) {
@@ -376,6 +384,13 @@ fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item {
       ast::ii_native(i) {
         ast::ii_native(fld.fold_native_item(i))
       }
+      ast::ii_ctor(ctor, nm, tps, parent_id) {
+        let ctor_body = fld.fold_block(ctor.node.body);
+        let ctor_decl = fold::fold_fn_decl(ctor.node.dec, fld);
+        ast::ii_ctor({node: {body: ctor_body, dec: ctor_decl
+                              with ctor.node}
+            with ctor}, nm, tps, parent_id)
+      }
     }
 }
 
@@ -403,7 +418,17 @@ fn renumber_ast(xcx: extended_decode_ctxt, ii: ast::inlined_item)
       ast::ii_native(i) {
         ast::ii_native(fld.fold_native_item(i))
       }
-    }
+      ast::ii_ctor(ctor, nm, tps, parent_id) {
+        let ctor_body = fld.fold_block(ctor.node.body);
+        let ctor_decl = fold::fold_fn_decl(ctor.node.dec, fld);
+        let new_params = fold::fold_ty_params(tps, fld);
+        let ctor_id = fld.new_id(ctor.node.id);
+        let new_parent = xcx.tr_def_id(parent_id);
+        ast::ii_ctor({node: {body: ctor_body, dec: ctor_decl, id: ctor_id
+                              with ctor.node}
+            with ctor}, nm, new_params, new_parent)
+      }
+     }
 }
 
 // ______________________________________________________________________
diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs
index 197f8be6f02..4587c1c740d 100644
--- a/src/rustc/metadata/encoder.rs
+++ b/src/rustc/metadata/encoder.rs
@@ -368,6 +368,7 @@ fn encode_privacy(ebml_w: ebml::writer, privacy: privacy) {
 /* Returns an index of items in this class */
 fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer,
                          id: node_id, path: ast_map::path,
+                         class_tps: [ty_param],
                          items: [@class_member],
                          global_index: @mut[entry<int>])
  -> [entry<int>] {
@@ -397,13 +398,10 @@ fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer,
                    but it works for now -- tjc */
                 *global_index += [{val: m.id, pos: ebml_w.writer.tell()}];
                 let impl_path = path + [ast_map::path_name(m.ident)];
-                /*
-                  Recall methods are (currently) monomorphic, and we don't
-                  repeat the class's ty params in the method decl
-                */
                 #debug("encode_info_for_class: doing %s %d", m.ident, m.id);
                 encode_info_for_method(ecx, ebml_w, impl_path,
-                                       should_inline(m.attrs), id, m, []);
+                                       should_inline(m.attrs), id, m,
+                                       class_tps + m.tps);
             }
             _ { /* don't encode private methods */ }
           }
@@ -415,7 +413,8 @@ fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer,
 
 fn encode_info_for_fn(ecx: @encode_ctxt, ebml_w: ebml::writer,
                       id: node_id, ident: ident, path: ast_map::path,
-                      item: option<@item>, tps: [ty_param], decl: fn_decl) {
+                      item: option<inlined_item>, tps: [ty_param],
+                      decl: fn_decl) {
         ebml_w.start_tag(tag_items_data_item);
         encode_name(ebml_w, ident);
         encode_def_id(ebml_w, local_def(id));
@@ -428,7 +427,7 @@ fn encode_info_for_fn(ecx: @encode_ctxt, ebml_w: ebml::writer,
         encode_path(ebml_w, path, ast_map::path_name(ident));
         alt item {
            some(it) {
-             astencode::encode_inlined_item(ecx, ebml_w, path, ii_item(it));
+             astencode::encode_inlined_item(ecx, ebml_w, path, it);
            }
            none {
              encode_symbol(ecx, ebml_w, id);
@@ -441,7 +440,7 @@ fn encode_info_for_method(ecx: @encode_ctxt, ebml_w: ebml::writer,
                           impl_path: ast_map::path, should_inline: bool,
                           parent_id: node_id,
                           m: @method, all_tps: [ty_param]) {
-    #debug("encode_info_for_method: %d %s", m.id, m.ident);
+    #debug("encode_info_for_method: %d %s %u", m.id, m.ident, all_tps.len());
     ebml_w.start_tag(tag_items_data_item);
     encode_def_id(ebml_w, local_def(m.id));
     encode_family(ebml_w, purity_fn_family(m.decl.purity));
@@ -562,8 +561,8 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
            These come first because we need to write them to make
            the index, and the index needs to be in the item for the
            class itself */
-        let idx = encode_info_for_class(ecx, ebml_w, item.id, path, items,
-                                          index);
+        let idx = encode_info_for_class(ecx, ebml_w, item.id, path, tps,
+                                          items, index);
         /* Index the class*/
         add_to_index();
         /* Now, make an item for the class itself */
@@ -594,6 +593,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
                 #debug("Writing %s %d", m.ident, m.id);
                 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();
@@ -727,7 +727,6 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer,
             alt check ecx.ccx.tcx.items.get(i.id) {
               ast_map::node_item(_, pt) {
                 encode_info_for_item(ecx, ebml_w, i, index, *pt);
-                /* TODO: encode info for class items! */
                 /* encode ctor, then encode items */
                 alt i.node {
                   item_class(tps,_,ctor) {
@@ -737,7 +736,10 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer,
                           ctor.node.id);
                    *index += [{val: ctor.node.id, pos: ebml_w.writer.tell()}];
                    encode_info_for_fn(ecx, ebml_w, ctor.node.id, i.ident,
-                                      *pt, none, tps, ctor.node.dec)
+                      *pt, if tps.len() > 0u {
+                             some(ii_ctor(ctor, i.ident, tps,
+                                          local_def(i.id))) }
+                           else { none }, tps, ctor.node.dec)
                   }
                   _ {}
                 }
diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs
index 46709abaa40..b4a6e194b38 100644
--- a/src/rustc/middle/ast_map.rs
+++ b/src/rustc/middle/ast_map.rs
@@ -44,10 +44,16 @@ enum ast_node {
     // order they are introduced.
     node_arg(arg, uint),
     node_local(uint),
-    node_ctor(@item, @path),
+    // Constructor for either a resource or a class
+    node_ctor(ident, [ty_param], a_ctor, @path),
     node_block(blk),
 }
 
+enum a_ctor {
+  res_ctor(fn_decl, node_id, codemap::span),
+  class_ctor(@class_ctor, def_id /* ID for parent class */),
+}
+
 type map = std::map::hashmap<node_id, ast_node>;
 type ctx = {map: map, mut path: path,
             mut local_id: uint, sess: session};
@@ -99,7 +105,7 @@ fn map_decoded_item(sess: session, map: map, path: path, ii: inlined_item) {
     // don't decode and instantiate the impl, but just the method, we have to
     // add it to the table now:
     alt ii {
-      ii_item(i) { /* fallthrough */ }
+      ii_item(_) | ii_ctor(_,_,_,_) { /* fallthrough */ }
       ii_native(i) {
         cx.map.insert(i.id, node_native_item(i, native_abi_rust_intrinsic,
                                              @path));
@@ -119,6 +125,16 @@ fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
         cx.map.insert(a.id, node_arg(a, cx.local_id));
         cx.local_id += 1u;
     }
+    alt fk {
+      visit::fk_ctor(nm, tps, self_id, parent_id) {
+          let ct = @{node: {id: id, self_id: self_id,
+                           dec: decl, body: body},
+                    span: sp};
+          cx.map.insert(id, node_ctor(nm, tps, class_ctor(ct, parent_id),
+                                      @cx.path));
+       }
+       _ {}
+    }
     visit::visit_fn(fk, decl, body, sp, id, cx, v);
 }
 
@@ -166,8 +182,10 @@ fn map_item(i: @item, cx: ctx, v: vt) {
             map_method(impl_did, extend(cx, i.ident), m, cx);
         }
       }
-      item_res(_, _, _, dtor_id, ctor_id) {
-        cx.map.insert(ctor_id, node_ctor(i, item_path));
+      item_res(decl, tps, _, dtor_id, ctor_id) {
+        cx.map.insert(ctor_id, node_ctor(i.ident, tps,
+                                         res_ctor(decl, ctor_id, i.span),
+                                         item_path));
         cx.map.insert(dtor_id, node_item(i, item_path));
       }
       item_enum(vs, _) {
@@ -186,7 +204,6 @@ fn map_item(i: @item, cx: ctx, v: vt) {
         }
       }
       item_class(_, items, ctor) {
-          cx.map.insert(ctor.node.id, node_ctor(i, item_path));
           let d_id = ast_util::local_def(i.id);
           let p = extend(cx, i.ident);
           for items.each {|ci|
@@ -267,7 +284,7 @@ fn node_id_to_str(map: map, id: node_id) -> str {
       some(node_local(_)) { // FIXME: add more info here
         #fmt["local (id=%?)", id]
       }
-      some(node_ctor(_, _)) { // FIXME: add more info here
+      some(node_ctor(_, _, _, _)) { // FIXME: add more info here
         #fmt["node_ctor (id=%?)", id]
       }
       some(node_block(_)) {
diff --git a/src/rustc/middle/mutbl.rs b/src/rustc/middle/mutbl.rs
index 633960f9351..d6488334311 100644
--- a/src/rustc/middle/mutbl.rs
+++ b/src/rustc/middle/mutbl.rs
@@ -214,15 +214,15 @@ fn visit_expr(ex: @expr, &&cx: @ctx, v: visit::vt<@ctx>) {
 
 fn visit_item(item: @item, &&cx: @ctx, v: visit::vt<@ctx>) {
     alt item.node {
-            item_class(tps, items, ctor) {
-                v.visit_ty_params(tps, cx, v);
-                vec::map::<@class_member, ()>(items,
-                    {|i| v.visit_class_item(i, cx, v); });
-                v.visit_fn(visit::fk_ctor(item.ident, tps), ctor.node.dec,
-                           ctor.node.body, ctor.span, ctor.node.id,
-                           @{in_ctor: some(ctor.node.self_id) with *cx}, v);
-            }
-            _ { visit::visit_item(item, cx, v); }
+      item_class(tps, items, ctor) {
+         v.visit_ty_params(tps, cx, v);
+         vec::map::<@class_member, ()>(items,
+             {|i| v.visit_class_item(i, cx, v); });
+         visit::visit_class_ctor_helper(ctor, item.ident, tps,
+                                        ast_util::local_def(item.id),
+                    @{in_ctor: some(ctor.node.self_id) with *cx}, v);
+      }
+      _ { visit::visit_item(item, cx, v); }
     }
 }
 
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index fc4ea88581e..611a3e36d05 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -572,7 +572,7 @@ fn visit_fn_with_scope(e: @env, fk: visit::fn_kind, decl: ast::fn_decl,
     for decl.constraints.each {|c| resolve_constr(e, c, sc, v); }
     let scope = alt fk {
       visit::fk_item_fn(_, tps) | visit::fk_res(_, tps) |
-      visit::fk_method(_, tps, _) | visit::fk_ctor(_, tps)
+      visit::fk_method(_, tps, _) | visit::fk_ctor(_, tps, _, _)
          { scope_bare_fn(decl, id, tps) }
       visit::fk_anon(ast::proto_bare) { scope_bare_fn(decl, id, []) }
       visit::fk_anon(_) | visit::fk_fn_block { scope_fn_expr(decl, id, []) }
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 93f88b158c2..fcb983a7291 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -1906,11 +1906,7 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
         ret {val: get_item_val(ccx, fn_id.node),
              must_cast: true};
       }
-      ast_map::node_ctor(i, _) {
-        alt check ccx.tcx.items.get(i.id) {
-          ast_map::node_item(i, pt) { (pt, i.ident) }
-        }
-      }
+      ast_map::node_ctor(nm, _, _, pt) { (pt, nm) }
       _ { fail "unexpected node type"; }
     };
     let mono_ty = ty::substitute_type_params(ccx.tcx, substs, item_ty);
@@ -1950,19 +1946,19 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
         trans_fn(ccx, pt, mth.decl, mth.body, lldecl,
                  impl_self(selfty), psubsts, fn_id.node);
       }
-      ast_map::node_ctor(i, _) {
-        alt check i.node {
-          ast::item_res(decl, _, _, _, _) {
+      ast_map::node_ctor(nm, tps, ct, _) {
+        alt ct {
+          ast_map::res_ctor(decl,_, _) {
             set_inline_hint(lldecl);
             trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, lldecl);
           }
-          ast::item_class(tps, _, ctor) {
-            set_inline_hint_if_appr(i.attrs, lldecl);
+          ast_map::class_ctor(ctor, parent_id) {
+            // ctors don't have attrs, at least not right now
             let tp_tys: [ty::t] = ty::ty_params_to_tys(ccx.tcx, tps);
             trans_class_ctor(ccx, pt, ctor.node.dec, ctor.node.body, lldecl,
                  option::get_or_default(psubsts,
                    {tys:tp_tys, vtables: none, bounds: @[]}),
-              fn_id.node, i.id, ctor.span);
+              fn_id.node, parent_id, ctor.span);
           }
         }
       }
@@ -1992,6 +1988,10 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id)
             trans_item(ccx, *item);
             local_def(item.id)
           }
+          csearch::found(ast::ii_ctor(ctor, nm, tps, parent_id)) {
+            ccx.external.insert(fn_id, some(ctor.node.id));
+            local_def(ctor.node.id)
+          }
           csearch::found(ast::ii_native(item)) {
             ccx.external.insert(fn_id, some(item.id));
             local_def(item.id)
@@ -4256,17 +4256,17 @@ fn trans_const(ccx: @crate_ctxt, e: @ast::expr, id: ast::node_id) {
 fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
                     body: ast::blk, llctor_decl: ValueRef,
                     psubsts: param_substs, ctor_id: ast::node_id,
-                    parent_id: ast::node_id, sp: span) {
+                    parent_id: ast::def_id, sp: span) {
   // Add ctor to the ctor map
   ccx.class_ctors.insert(ctor_id, parent_id);
+
   // Translate the ctor
 
   // Set up the type for the result of the ctor
   // kludgy -- this wouldn't be necessary if the typechecker
   // special-cased constructors, then we could just look up
   // the ctor's return type.
-  let rslt_ty =  ty::mk_class(ccx.tcx, local_def(parent_id),
-                                    psubsts.tys);
+  let rslt_ty =  ty::mk_class(ccx.tcx, parent_id, psubsts.tys);
   // Make the fn context
   let fcx = new_fn_ctxt_w_id(ccx, path, llctor_decl, ctor_id,
                                    some(psubsts), some(sp));
@@ -4280,10 +4280,10 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
   // We *don't* want self to be passed to the ctor -- that
   // wouldn't make sense
   // So we initialize it here
+
   let selfptr = alloc_ty(bcx_top, rslt_ty);
   // initialize fields to zero
-  let fields = ty::class_items_as_fields(bcx_top.tcx(),
-                                         local_def(parent_id),
+  let fields = ty::class_items_as_fields(bcx_top.tcx(), parent_id,
                                          psubsts.tys);
   let mut bcx = bcx_top;
   // Initialize fields to zero so init assignments can validly
@@ -4381,7 +4381,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
                          bounds: @[]};
           trans_class_ctor(ccx, *path, ctor.node.dec, ctor.node.body,
                          get_item_val(ccx, ctor.node.id), psubsts,
-                         ctor.node.id, item.id, ctor.span);
+                           ctor.node.id, local_def(item.id), ctor.span);
         }
         // If there are ty params, the ctor will get monomorphized
 
@@ -4542,6 +4542,7 @@ fn item_path(ccx: @crate_ctxt, i: @ast::item) -> path {
 }
 
 fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
+    #debug("get_item_val: %d", id);
     alt ccx.item_vals.find(id) {
       some(v) { v }
       none {
@@ -4593,16 +4594,16 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
             exprt = true;
             register_fn(ccx, ni.span, *pth + [path_name(ni.ident)], ni.id)
           }
-          ast_map::node_ctor(i, _) {
-            alt check i.node {
-              ast::item_res(_, _, _, _, _) {
-                let my_path = item_path(ccx, i);
-                let llctor = register_fn(ccx, i.span, my_path, id);
+          ast_map::node_ctor(nm, tps, ct, pt) {
+            let my_path = *pt + [path_name(nm)];
+            alt ct {
+              ast_map::res_ctor(_,_,sp) {
+                let llctor = register_fn(ccx, sp, my_path, id);
                 set_inline_hint(llctor);
                 llctor
               }
-              ast::item_class(_, _, ctor) {
-                register_fn(ccx, i.span, item_path(ccx, i), id)
+              ast_map::class_ctor(ctor, _) {
+                register_fn(ccx, ctor.span, my_path, ctor.node.id)
               }
             }
           }
@@ -4923,7 +4924,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
           shape_cx: mk_ctxt(llmod),
           crate_map: crate_map,
           dbg_cx: dbg_cx,
-          class_ctors: int_hash::<int>(),
+          class_ctors: int_hash::<ast::def_id>(),
           mut do_not_commit_warning_issued: false};
 
 
diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs
index c089361bda0..36c75398b99 100644
--- a/src/rustc/middle/trans/common.rs
+++ b/src/rustc/middle/trans/common.rs
@@ -121,7 +121,9 @@ type crate_ctxt = {
      dbg_cx: option<debuginfo::debug_ctxt>,
      // Mapping from class constructors to parent class --
      // used in base::trans_closure
-     class_ctors: hashmap<ast::node_id, ast::node_id>,
+     // parent_class must be a def_id because ctors can be
+     // inlined, so the parent may be in a different crate
+     class_ctors: hashmap<ast::node_id, ast::def_id>,
      mut do_not_commit_warning_issued: bool};
 
 // Types used for llself.
diff --git a/src/rustc/middle/trans/debuginfo.rs b/src/rustc/middle/trans/debuginfo.rs
index 42f762ac1b5..5406ec7ce98 100644
--- a/src/rustc/middle/trans/debuginfo.rs
+++ b/src/rustc/middle/trans/debuginfo.rs
@@ -757,13 +757,14 @@ fn create_function(fcx: fn_ctxt) -> @metadata<subprogram_md> {
       ast_map::node_method(method, _, _) {
           (method.ident, method.decl.output, method.id)
       }
-      ast_map::node_ctor(item, _) {
-        alt item.node {
-            ast::item_res(decl, _, _, _, ctor_id) {
-              (item.ident, decl.output, ctor_id)
-            }
-            _ { fcx.ccx.sess.span_bug(item.span, "create_function: \
-                  expected an item_res here"); }
+      ast_map::node_ctor(nm, _, ct, _) {
+        alt ct {
+          ast_map::res_ctor(decl, ctor_id, _) {
+            (nm, decl.output, ctor_id)
+          }
+          ast_map::class_ctor(ctor,_) {
+            fcx.ccx.sess.span_bug(ctor.span, "create_function: \
+                  expected a resource ctor here"); }
           }
       }
       ast_map::node_expr(expr) {
diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs
index b220f30a5ac..cbed8a0dbc5 100644
--- a/src/rustc/middle/trans/type_use.rs
+++ b/src/rustc/middle/trans/type_use.rs
@@ -58,13 +58,18 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
         ccx.type_use_cache.insert(fn_id, uses);
         ret uses;
     }
-    alt check ccx.tcx.items.get(fn_id_loc.node) {
+    let map_node = alt ccx.tcx.items.find(fn_id_loc.node) {
+        some(x) { x }
+        none    { ccx.sess.bug(#fmt("type_uses_for: unbound item ID %?",
+                                    fn_id_loc)); }
+    };
+    alt check map_node {
       ast_map::node_item(@{node: item_fn(_, _, body), _}, _) |
       ast_map::node_item(@{node: item_res(_, _, body, _, _), _}, _) |
       ast_map::node_method(@{body, _}, _, _) {
         handle_body(cx, body);
       }
-      ast_map::node_ctor(@{node: item_res(_, _, _, _, _), _},_) |
+      ast_map::node_ctor(_, _, ast_map::res_ctor(_, _, _), _) |
       ast_map::node_variant(_, _, _) {
         uint::range(0u, n_tps) {|n| cx.uses[n] |= use_repr;}
       }
@@ -79,7 +84,7 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint)
             uint::range(0u, n_tps) {|n| cx.uses[n] |= flags;}
         }
       }
-      ast_map::node_ctor(@{node: item_class(_, _, ctor), _}, _) {
+      ast_map::node_ctor(_, _, ast_map::class_ctor(ctor, _), _){
         handle_body(cx, ctor.node.body);
       }
     }
diff --git a/src/rustc/middle/tstate/ck.rs b/src/rustc/middle/tstate/ck.rs
index decf1af6401..c04d9ad1e75 100644
--- a/src/rustc/middle/tstate/ck.rs
+++ b/src/rustc/middle/tstate/ck.rs
@@ -111,7 +111,7 @@ fn check_states_against_conditions(fcx: fn_ctxt,
 
     /* Check that the return value is initialized */
     let post = aux::block_poststate(fcx.ccx, f_body);
-    let is_ctor = alt fk { visit::fk_ctor(_,_) { true } _ { false } };
+    let is_ctor = alt fk { visit::fk_ctor(_,_,_,_) { true } _ { false } };
     if !is_ctor && !promises(fcx, post, fcx.enclosing.i_return) &&
        !ty::type_is_nil(ty::ty_fn_ret(ty::node_id_to_type(
            fcx.ccx.tcx, id))) &&
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 094d2f90d5d..f4d134459be 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -2043,8 +2043,8 @@ fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
             vec::init(*path) + [ast_map::path_name(variant.node.name)]
           }
 
-          ast_map::node_ctor(i, path) {
-              *path + [ast_map::path_name(i.ident)]
+          ast_map::node_ctor(nm, _, _, path) {
+              *path + [ast_map::path_name(nm)]
           }
 
           ast_map::node_expr(_) | ast_map::node_arg(_, _) |
@@ -2121,7 +2121,6 @@ fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
     alt cx.tcache.find(did) {
       some(tpt) { ret tpt; }
       none {
-          #debug("lookup_item_type: looking up %?", did);
         // The item is in this crate. The caller should have added it to the
         // type cache already
         assert did.crate != ast::local_crate;
@@ -2168,7 +2167,10 @@ fn lookup_class_fields(cx: ctxt, did: ast::def_id) -> [field_ty] {
            _ { cx.sess.bug("class ID bound to non-class"); }
          }
        }
-       _ { cx.sess.bug("class ID not bound to an item"); }
+       _ {
+           cx.sess.bug(#fmt("class ID not bound to an item: %s",
+                            ast_map::node_id_to_str(cx.items, did.node)));
+       }
     }
         }
   else {
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 83b07b9e86c..f89a34e668f 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -2149,6 +2149,20 @@ fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} {
     }
 }
 
+/*
+  Takes arguments describing a method, and returns either its origin,
+  or <none> if it's unbound.
+
+  expr: the entire method reference
+  node_id: the method's ID
+  name: the method's name
+  ty: the type of the base expression
+  tps: the ty substitutions that are part of the field expr
+    (for example: in foo.bar<int,char>(), tps would be
+     [int, char])
+  include_private: true if we're inside the same class and should
+     search private methods
+ */
 fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
                  name: ast::ident, ty: ty::t, tps: [ty::t],
                  include_private: bool)
@@ -2159,7 +2173,12 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
         let mut substs = substs;
         let n_tps = vec::len(substs), n_tys = vec::len(tps);
         let has_self = ty::type_has_vars(fty);
+        /* If either the method was declared to have ty params,
+         or ty arguments were provided, or both... */
         if method_n_tps + n_tps > 0u {
+          /* If no type arguments were given,
+             or a different number of them were given than the
+             method's declared types... */
             if n_tys == 0u || n_tys != method_n_tps {
                 if n_tys != 0u {
                     tcx.sess.span_err
@@ -2167,12 +2186,18 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
                                      parameters given for this method");
 
                 }
+                /* If not enough types were given, make some ty vars */
                 substs += vec::from_fn(method_n_tps, {|_i|
                     ty::mk_var(tcx, next_ty_var_id(fcx))
                 });
             } else {
+             /* If the right number of types were given, just add them on */
                 substs += tps;
             }
+            /*
+              For a class method, "substs" here begins with the class ty
+              params
+             */
             fcx.write_ty_substs(node_id, fty, substs);
         } else {
             if n_tys > 0u {
@@ -2209,7 +2234,6 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
                         include_private: bool)
     -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
         origin: method_origin, self_sub: option<self_subst>}> {
-    #debug("lookup_method_inner_: %? %? %s", ms, parent, name);
     let mut i = 0u;
     for ms.each {|m|
        if m.ident == name {
@@ -2228,6 +2252,8 @@ fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
                         sp, "Call to private method not allowed outside \
                           its defining class");
           }
+          #debug("lookup_method_inner_: %s has %u ty params, by its \
+            declaration", name, vec::len(*m.tps));
           ret some({method_ty: fty,
                     n_tps: vec::len(*m.tps),
                     substs: tps,
diff --git a/src/test/auxiliary/cci_class_6.rs b/src/test/auxiliary/cci_class_6.rs
new file mode 100644
index 00000000000..15fa3e3e785
--- /dev/null
+++ b/src/test/auxiliary/cci_class_6.rs
@@ -0,0 +1,21 @@
+mod kitties {
+
+class cat<U> {
+  priv {
+    let mut info : [U];
+    let mut meows : uint;
+  }
+
+  let how_hungry : int;
+
+  new(in_x : uint, in_y : int, -in_info: [U])
+    { self.meows = in_x; self.how_hungry = in_y;
+      self.info <- in_info; }
+
+  fn speak<T>(stuff: [T]) {
+    self.meows += stuff.len();
+  }
+  fn meow_count() -> uint { self.meows }
+}
+
+}
diff --git a/src/test/run-pass/class-poly-methods-cross-crate.rs b/src/test/run-pass/class-poly-methods-cross-crate.rs
new file mode 100644
index 00000000000..28ddbfdd1e2
--- /dev/null
+++ b/src/test/run-pass/class-poly-methods-cross-crate.rs
@@ -0,0 +1,15 @@
+// xfail-fast
+// aux-build:cci_class_6.rs
+use cci_class_6;
+import cci_class_6::kitties::*;
+
+fn main() {
+  let nyan : cat<char> = cat::<char>(52u, 99, ['p']);
+  let kitty = cat(1000u, 2, ["tabby"]);
+  assert(nyan.how_hungry == 99);
+  assert(kitty.how_hungry == 2);
+  nyan.speak([1u,2u,3u]);
+  assert(nyan.meow_count() == 55u);
+  kitty.speak(["meow", "mew", "purr", "chirp"]);
+  assert(kitty.meow_count() == 1004u);
+}
diff --git a/src/test/run-pass/class-poly-methods.rs b/src/test/run-pass/class-poly-methods.rs
index 0a96b1754d5..0d738913ee5 100644
--- a/src/test/run-pass/class-poly-methods.rs
+++ b/src/test/run-pass/class-poly-methods.rs
@@ -1,5 +1,3 @@
-// xfail-test
-// needs metadata encoding on Windows
 class cat<U> {
   priv {
     let mut info : [U];