about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-03-19 10:19:00 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-03-20 17:07:07 -0700
commitb06dc884e57644a0c7e9c5391af9e0392e5f49ac (patch)
tree1d1578a0f5770193799937b84cdcc96b217e52e9
parent855c99ea758186096a68a8c13edeb0d89105a410 (diff)
downloadrust-b06dc884e57644a0c7e9c5391af9e0392e5f49ac.tar.gz
rust-b06dc884e57644a0c7e9c5391af9e0392e5f49ac.zip
Class methods WIP
In particular, use the ast::method type to represent a class method,
and try to reuse as much iface code as possible. (This makes sense now
since I'll be allowing polymorphic class methods.)
-rw-r--r--src/rustc/driver/session.rs8
-rw-r--r--src/rustc/metadata/csearch.rs31
-rw-r--r--src/rustc/metadata/decoder.rs46
-rw-r--r--src/rustc/metadata/encoder.rs159
-rw-r--r--src/rustc/middle/ast_map.rs13
-rw-r--r--src/rustc/middle/resolve.rs4
-rw-r--r--src/rustc/middle/trans/reachable.rs11
-rw-r--r--src/rustc/middle/trans/type_of.rs16
-rw-r--r--src/rustc/middle/ty.rs83
-rw-r--r--src/rustc/middle/typeck.rs182
-rw-r--r--src/rustc/syntax/ast.rs4
-rw-r--r--src/rustc/syntax/ast_util.rs16
-rw-r--r--src/rustc/syntax/fold.rs6
-rw-r--r--src/rustc/syntax/parse/parser.rs32
-rw-r--r--src/rustc/syntax/print/pprust.rs20
-rw-r--r--src/rustc/syntax/visit.rs4
-rw-r--r--src/test/run-pass/classes-simple-method.rs8
17 files changed, 384 insertions, 259 deletions
diff --git a/src/rustc/driver/session.rs b/src/rustc/driver/session.rs
index 081b18b08dd..d48ca3f495e 100644
--- a/src/rustc/driver/session.rs
+++ b/src/rustc/driver/session.rs
@@ -110,6 +110,14 @@ impl session for session {
     }
 }
 
+// Seems out of place, but it uses session, so I'm putting it here
+fn expect<T: copy>(sess: session, opt: option<T>, msg: fn() -> str) -> T {
+    alt opt {
+       some(t) { t }
+       none { sess.bug(msg()); }
+    }
+}
+
 fn building_library(req_crate_type: crate_type, crate: @ast::crate,
                     testing: bool) -> bool {
     alt req_crate_type {
diff --git a/src/rustc/metadata/csearch.rs b/src/rustc/metadata/csearch.rs
index e6615197c01..1d8965897ad 100644
--- a/src/rustc/metadata/csearch.rs
+++ b/src/rustc/metadata/csearch.rs
@@ -1,15 +1,19 @@
 // Searching for information from the cstore
 
+import std::{ebml};
 import syntax::ast;
 import syntax::ast_util;
 import middle::{ty, ast_map};
 import option::{some, none};
 import driver::session;
+import driver::session::expect;
 import middle::trans::common::maps;
+import common::*;
 import std::map::hashmap;
 
 export get_symbol;
-export get_class_items;
+export get_class_fields;
+export get_field_type;
 export get_type_param_count;
 export lookup_defs;
 export lookup_method_purity;
@@ -120,10 +124,10 @@ fn get_iface_methods(tcx: ty::ctxt, def: ast::def_id) -> @[ty::method] {
     decoder::get_iface_methods(cdata, def.node, tcx)
 }
 
-fn get_class_items(tcx: ty::ctxt, def: ast::def_id) -> [@ty::class_item_ty] {
+fn get_class_fields(tcx: ty::ctxt, def: ast::def_id) -> [ty::field_ty] {
     let cstore = tcx.sess.cstore;
     let cdata = cstore::get_crate_data(cstore, def.crate);
-    decoder::get_class_items(cdata, def.node, tcx)
+    decoder::get_class_fields(tcx, cdata, def.node)
 }
 
 fn get_type(tcx: ty::ctxt, def: ast::def_id) -> ty::ty_param_bounds_and_ty {
@@ -132,6 +136,27 @@ fn get_type(tcx: ty::ctxt, def: ast::def_id) -> ty::ty_param_bounds_and_ty {
     decoder::get_type(cdata, def.node, tcx)
 }
 
+/* FIXME: Refactor */
+fn get_field_type(tcx: ty::ctxt, class_id: ast::def_id,
+                  def: ast::def_id) -> ty::ty_param_bounds_and_ty {
+    let cstore = tcx.sess.cstore;
+    let cdata = cstore::get_crate_data(cstore, class_id.crate);
+    let all_items = ebml::get_doc(ebml::doc(cdata.data), tag_items);
+    #debug("Looking up %?", class_id);
+    let class_doc = expect(tcx.sess,
+                           decoder::maybe_find_item(class_id.node, all_items),
+                           {|| #fmt("get_field_type: class ID %? not found",
+                     class_id)});
+    #debug("looking up %? : %?", def, class_doc);
+    let the_field = expect(tcx.sess,
+        decoder::maybe_find_item(def.node, class_doc),
+        {|| #fmt("get_field_type: in class %?, field ID %? not found",
+                 class_id, def)});
+    #debug("got field data %?", the_field);
+    let ty = decoder::item_type(def, the_field, tcx, cdata);
+    ret {bounds: @[], ty: ty};
+}
+
 fn get_impl_iface(tcx: ty::ctxt, def: ast::def_id)
     -> option<ty::t> {
     let cstore = tcx.sess.cstore;
diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs
index 1a3f6123d57..8916d32d393 100644
--- a/src/rustc/metadata/decoder.rs
+++ b/src/rustc/metadata/decoder.rs
@@ -14,8 +14,9 @@ import tydecode::{parse_ty_data, parse_def_id, parse_bounds_data,
 import syntax::print::pprust;
 import cmd=cstore::crate_metadata;
 import middle::trans::common::maps;
+import util::ppaux::ty_to_str;
 
-export get_class_items;
+export get_class_fields;
 export get_symbol;
 export get_enum_variants;
 export get_type;
@@ -35,6 +36,8 @@ export get_impls_for_mod;
 export get_iface_methods;
 export get_crate_module_paths;
 export get_item_path;
+export maybe_find_item; // sketchy
+export item_type; // sketchy
 export maybe_get_item_ast;
 export item_is_intrinsic;
 
@@ -110,9 +113,9 @@ fn item_parent_item(d: ebml::doc) -> option<ast::def_id> {
     found
 }
 
-fn class_field_id(d: ebml::doc) -> ast::def_id {
+fn class_field_id(d: ebml::doc, cdata: cmd) -> ast::def_id {
     let tagdoc = ebml::get_doc(d, tag_def_id);
-    ret parse_def_id(ebml::doc_data(tagdoc));
+    ret translate_def_id(cdata, parse_def_id(ebml::doc_data(tagdoc)));
 }
 
 fn variant_disr_val(d: ebml::doc) -> option<int> {
@@ -406,37 +409,26 @@ fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
 }
 
 /* Take a node ID for a class, return a vector of the class's
- member types */
-fn get_class_items(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
-    -> [@ty::class_item_ty] {
+   field names/IDs */
+fn get_class_fields(tcx: ty::ctxt,
+               cdata: cmd, id: ast::node_id) -> [ty::field_ty] {
     let data = cdata.data;
     let item = lookup_item(id, data), result = [];
-    #debug("get_class_items: %s", item_name(item));
-    #debug("item: %?", item);
-    // right tag?
-    ebml::tagged_docs(item, tag_items_class_member) {|an_item|
+    ebml::tagged_docs(item, tag_items_data_item) {|an_item|
         let fam = item_family(an_item);
-        let decl = alt check fam {
-                'g' {
-                    let name = item_name(an_item);
-                    #debug("why hello there! %s", name);
-                    let ty = doc_type(an_item, tcx, cdata);
-                    let did = class_field_id(an_item);
-                    {ident: name,
-                     id: did.node,
-                     contents: ty::var_ty(ty)}
-                }
-                _ {
-                    fail; // FIXME
-                }
-        };
-        result += [@decl];
+        alt fam {
+         'g' {
+             let name = item_name(an_item);
+             let _ty = doc_type(an_item, tcx, cdata);
+             let did = class_field_id(an_item, cdata);
+             result += [{ident: name, id: did}];
+         }
+        _ { /* this only handles fields */}
+       }
     }
     result
 }
 
-
-
 fn family_has_type_params(fam_ch: char) -> bool {
     alt check fam_ch {
       'c' | 'T' | 'm' | 'n' | 'g' | 'h' { false }
diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs
index e36b982ff12..b55a3426244 100644
--- a/src/rustc/metadata/encoder.rs
+++ b/src/rustc/metadata/encoder.rs
@@ -82,8 +82,8 @@ fn encode_class_item_paths(ebml_w: ebml::writer,
           priv { cont; }
           pub {
               let (id, ident) = alt it.node.decl {
-                      instance_var(v, _, _, vid) { (vid, v) }
-                      class_method(it) { (it.id, it.ident) }
+                 instance_var(v, _, _, vid) { (vid, v) }
+                 class_method(it) { (it.id, it.ident) }
               };
               add_to_index(ebml_w, path, index, ident);
               encode_named_def_id(ebml_w, ident, local_def(id));
@@ -145,18 +145,18 @@ fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt,
             ebml_w.end_tag();
           }
           item_class(tps,items,ctor) {
-              add_to_index(ebml_w, path, index, it.ident);
-              ebml_w.start_tag(tag_paths_data_item);
-              encode_name(ebml_w, it.ident);
-              encode_def_id(ebml_w, local_def(it.id));
-              ebml_w.end_tag();
-              ebml_w.start_tag(tag_paths);
-              add_to_index(ebml_w, path, index, it.ident);
-              #debug("ctor id: %d", ctor.node.id);
-              encode_named_def_id(ebml_w, it.ident, local_def(ctor.node.id));
-              encode_class_item_paths(ebml_w, items, path + [it.ident],
+            add_to_index(ebml_w, path, index, it.ident);
+            ebml_w.start_tag(tag_paths_data_item);
+            encode_name(ebml_w, it.ident);
+            encode_def_id(ebml_w, local_def(it.id));
+            ebml_w.end_tag();
+            ebml_w.start_tag(tag_paths);
+            add_to_index(ebml_w, path, index, it.ident);
+            #debug("ctor id: %d", ctor.node.id);
+            encode_named_def_id(ebml_w, it.ident, local_def(ctor.node.id));
+            encode_class_item_paths(ebml_w, items, path + [it.ident],
                                       index);
-              ebml_w.end_tag();
+            ebml_w.end_tag();
           }
           item_enum(variants, tps) {
             add_to_index(ebml_w, path, index, it.ident);
@@ -252,7 +252,12 @@ fn encode_type(ecx: @encode_ctxt, ebml_w: ebml::writer, typ: ty::t) {
 
 fn encode_symbol(ecx: @encode_ctxt, ebml_w: ebml::writer, id: node_id) {
     ebml_w.start_tag(tag_items_data_item_symbol);
-    ebml_w.writer.write(str::bytes(ecx.ccx.item_symbols.get(id)));
+    let sym = alt ecx.ccx.item_symbols.find(id) {
+      some(x) { x }
+      none { ecx.ccx.tcx.sess.bug(#fmt("encode_symbol: \
+                    id not found %d", id)); }
+    };
+    ebml_w.writer.write(str::bytes(sym));
     ebml_w.end_tag();
 }
 
@@ -346,43 +351,53 @@ fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::writer, md: _mod,
     ebml_w.end_tag();
 }
 
+/* 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, name: ident,
-                         tps: [ty_param], items: [@class_item]) {
+                         tps: [ty_param], items: [@class_item])
+ -> [entry<int>] {
+    let index = @mutable [];
+
     let tcx = ecx.ccx.tcx;
     encode_def_id(ebml_w, local_def(id));
     encode_family(ebml_w, 'C');
     encode_type_param_bounds(ebml_w, ecx, tps);
     encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
     encode_name(ebml_w, name);
+    encode_path(ebml_w, path, ast_map::path_name(name));
 
     for ci in items {
-            /* We encode both private and public fields -- need to include
-             private fields to get the offsets right */
-            ebml_w.start_tag(tag_items_class_member);
-            alt ci.node.decl {
-               instance_var(nm, _, _, id) {
-                   #debug("encode_info_for_class: doing %s %d", nm, id);
-                   encode_family(ebml_w, 'g');
-                   encode_name(ebml_w, nm);
-                   encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
-                   /* TODO: mutability */
-                   encode_def_id(ebml_w, local_def(id));
-               }
-               class_method(it) {
-                   encode_family(ebml_w, 'h');
-                   encode_name(ebml_w, it.ident);
-                   alt it.node {
-                      item_fn(fdecl, tps, _) {
-                          encode_info_for_fn(ecx, ebml_w, it.id, it.ident,
-                                             path, none, tps, fdecl);
-                      }
-                      _ { fail; /* TODO */ }
-                   }
-               }
-            }
-            ebml_w.end_tag();
+     /* We encode both private and public fields -- need to include
+        private fields to get the offsets right */
+      alt ci.node.decl {
+        instance_var(nm, _, _, id) {
+          *index += [{val: id, pos: ebml_w.writer.tell()}];
+          ebml_w.start_tag(tag_items_data_item);
+          #debug("encode_info_for_class: doing %s %d", nm, id);
+          encode_family(ebml_w, 'g');
+          encode_name(ebml_w, nm);
+          encode_path(ebml_w, path, ast_map::path_name(nm));
+          encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
+          /* TODO: mutability */
+          encode_def_id(ebml_w, local_def(id));
+        }
+        class_method(m) {
+          *index += [{val: m.id, pos: ebml_w.writer.tell()}];
+          ebml_w.start_tag(tag_items_data_item);
+          encode_family(ebml_w, 'h');
+          encode_name(ebml_w, m.ident);
+          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
+          */
+          encode_info_for_method(ecx, ebml_w, impl_path,
+                                 should_inline(m.attrs), id, m, []);
+        }
+      }
+      ebml_w.end_tag();
     }
+    *index
 }
 
 fn encode_info_for_fn(ecx: @encode_ctxt, ebml_w: ebml::writer,
@@ -408,6 +423,28 @@ fn encode_info_for_fn(ecx: @encode_ctxt, ebml_w: ebml::writer,
         ebml_w.end_tag();
 }
 
+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);
+    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));
+    encode_type_param_bounds(ebml_w, ecx, all_tps);
+    encode_type(ecx, ebml_w, node_id_to_type(ecx.ccx.tcx, m.id));
+    encode_name(ebml_w, m.ident);
+    encode_path(ebml_w, impl_path, ast_map::path_name(m.ident));
+    if all_tps.len() > 0u || should_inline {
+        astencode::encode_inlined_item(
+           ecx, ebml_w, impl_path,
+           ii_method(local_def(parent_id), m));
+    } else {
+        encode_symbol(ecx, ebml_w, m.id);
+    }
+    ebml_w.end_tag();
+}
+
 fn purity_fn_family(p: purity) -> char {
     alt p {
       unsafe_fn { 'u' }
@@ -417,15 +454,17 @@ fn purity_fn_family(p: purity) -> char {
     }
 }
 
-fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
-                        index: @mutable [entry<int>], path: ast_map::path) {
 
-    fn should_inline(attrs: [attribute]) -> bool {
-        alt attr::find_inline_attr(attrs) {
-          attr::ia_none { false }
-          attr::ia_hint | attr::ia_always { true }
-        }
+fn should_inline(attrs: [attribute]) -> bool {
+    alt attr::find_inline_attr(attrs) {
+        attr::ia_none { false }
+        attr::ia_hint | attr::ia_always { true }
     }
+}
+
+
+fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
+                        index: @mutable [entry<int>], path: ast_map::path) {
 
     let tcx = ecx.ccx.tcx;
     let must_write = alt item.node { item_enum(_, _) { true } _ { false } };
@@ -494,11 +533,12 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
                                  path, index, tps);
       }
       item_class(tps,items,ctor) {
-          /* We're not forgetting about the ctor here! It gets
-             encoded elsewhere */
         ebml_w.start_tag(tag_items_data_item);
-        encode_info_for_class(ecx, ebml_w, item.id, path, item.ident,
-                               tps, items);
+        let idx = encode_info_for_class(ecx, ebml_w, item.id, path,
+                 item.ident, tps, items);
+        /* each class must have its own index */
+        let bkts = create_index(idx, hash_node_id);
+        encode_index(ebml_w, bkts, write_int);
         ebml_w.end_tag();
       }
       item_res(_, tps, _, _, ctor_id) {
@@ -553,21 +593,8 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
         let impl_path = path + [ast_map::path_name(item.ident)];
         for m in methods {
             *index += [{val: m.id, pos: ebml_w.writer.tell()}];
-            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));
-            encode_type_param_bounds(ebml_w, ecx, tps + m.tps);
-            encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id));
-            encode_name(ebml_w, m.ident);
-            encode_path(ebml_w, impl_path, ast_map::path_name(m.ident));
-            if tps.len() > 0u || m.tps.len() > 0u || should_inline(m.attrs) {
-                astencode::encode_inlined_item(
-                    ecx, ebml_w, impl_path,
-                    ii_method(local_def(item.id), m));
-            } else {
-                encode_symbol(ecx, ebml_w, m.id);
-            }
-            ebml_w.end_tag();
+            encode_info_for_method(ecx, ebml_w, impl_path,
+                   should_inline(m.attrs), item.id, m, tps + m.tps);
         }
       }
       item_iface(tps, ms) {
diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs
index 1b2dbaf9d58..947dbaab2f6 100644
--- a/src/rustc/middle/ast_map.rs
+++ b/src/rustc/middle/ast_map.rs
@@ -172,8 +172,19 @@ fn map_item(i: @item, cx: ctx, v: vt) {
             cx.map.insert(nitem.id, node_native_item(nitem, abi, @cx.path));
         }
       }
-      item_class(_, _, ctor) {
+      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 ci in items {
+           // only need to handle methods
+           alt ci.node.decl {
+             class_method(m) {
+               map_method(d_id, p, m, cx);
+             }
+             _ {}
+           }
+          }
       }
       _ { }
     }
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index 25996dcdf90..e2bb5494659 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -531,7 +531,9 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
         /* visit the items */
         for cm in members {
             alt cm.node.decl {
-              class_method(i) { visit_item_with_scope(e, i, class_scope, v); }
+              class_method(m) { visit_fn_with_scope(e,
+                 visit::fk_item_fn(m.ident, tps), m.decl, m.body,
+                 m.span, m.id, class_scope, v); }
               instance_var(_,t,_,_) { v.visit_ty(t, class_scope, v); }
             }
         }
diff --git a/src/rustc/middle/trans/reachable.rs b/src/rustc/middle/trans/reachable.rs
index eabb3c0cd5c..da0067400e0 100644
--- a/src/rustc/middle/trans/reachable.rs
+++ b/src/rustc/middle/trans/reachable.rs
@@ -102,14 +102,11 @@ fn traverse_public_item(cx: ctx, item: @item) {
         cx.rmap.insert(ctor.node.id, ());
         for item in items {
             alt item.node.decl {
-              class_method(i) {
-                cx.rmap.insert(i.id, ());
+              class_method(m) {
+                cx.rmap.insert(m.id, ());
                 if tps.len() > 0u ||
-                   attr::find_inline_attr(i.attrs) != attr::ia_none {
-                    alt i.node {
-                      item_fn(_, _, blk) { traverse_inline_body(cx, blk); }
-                      _ {}
-                    }
+                   attr::find_inline_attr(m.attrs) != attr::ia_none {
+                    traverse_inline_body(cx, m.body);
                 }
               }
               _ {}
diff --git a/src/rustc/middle/trans/type_of.rs b/src/rustc/middle/trans/type_of.rs
index 77cf5e578d4..fcc2229ffbb 100644
--- a/src/rustc/middle/trans/type_of.rs
+++ b/src/rustc/middle/trans/type_of.rs
@@ -83,16 +83,12 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
       ty::ty_constr(subt,_) { type_of(cx, subt) }
       ty::ty_class(did, _) {
         let tys: [TypeRef] = [];
-        let cls_items = lookup_class_item_tys(cx.tcx, did);
-        for ci in cls_items {
-            // only instance vars are record fields at runtime
-            alt ci.contents {
-                var_ty(t) {
-                  let fty = type_of(cx, t);
-                  tys += [fty];
-                }
-                _ {}
-            }
+        // only instance vars are record fields at runtime
+        let fields = lookup_class_fields(cx.tcx, did);
+        for f in fields {
+            let t = ty::lookup_field_type(cx.tcx, did, f.id);
+            let fty = type_of(cx, t);
+            tys += [fty];
         }
         T_struct(tys)
       }
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index fd9765e3fc3..4a9f109e4e6 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -20,8 +20,6 @@ export arg;
 export args_eq;
 export ast_constr_to_constr;
 export block_ty;
-export class_contents_ty;
-export class_item_ty;
 export class_items_as_fields;
 export constr;
 export constr_general;
@@ -32,6 +30,7 @@ export expr_has_ty_params;
 export expr_ty;
 export expr_ty_params_and_ty;
 export expr_is_lval;
+export field_ty;
 export fold_ty;
 export field;
 export field_idx;
@@ -41,7 +40,8 @@ export fm_general, fm_rptr;
 export get_element_type;
 export is_binopable;
 export is_pred_ty;
-export lookup_class_item_tys;
+export lookup_class_fields;
+export lookup_field_type;
 export lookup_item_type;
 export method;
 export method_idx;
@@ -158,17 +158,12 @@ type constr_table = hashmap<ast::node_id, [constr]>;
 
 type mt = {ty: t, mutbl: ast::mutability};
 
-type class_item_ty = {
+// Just use <field> for class fields?
+type field_ty = {
   ident: ident,
-  id: node_id,
-  contents: class_contents_ty
+  id: def_id,
 };
 
-enum class_contents_ty {
-  var_ty(t),   // FIXME: need mutability, too
-  method_ty(fn_decl)
-}
-
 // Contains information needed to resolve types and (in the future) look up
 // the types of AST nodes.
 type creader_cache = hashmap<{cnum: int, pos: uint, len: uint}, t>;
@@ -1971,6 +1966,9 @@ mod unify {
         cx: @uctxt, expected: t, actual: t,
         variance: variance, nxt: fn(t) -> ures<T>) -> ures<T> {
 
+        #debug("unify_step: %s %s", ty_to_str(cx.tcx, expected),
+               ty_to_str(cx.tcx, actual));
+
         // Fast path.
         if expected == actual { ret nxt(expected); }
 
@@ -2434,15 +2432,40 @@ fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
     }
 }
 
+// Look up a field ID, whether or not it's local
+fn lookup_field_type(tcx: ctxt, class_id: def_id, id: def_id) -> ty::t {
+    if id.crate == ast::local_crate {
+            /*
+        alt items.find(tcx.items, id.node) {
+           some(ast_map::node_item({node: item_class(_,items,
+        }
+            */
+        node_id_to_type(tcx, id.node)
+    }
+    else {
+        alt tcx.tcache.find(id) {
+           some(tpt) { ret tpt.ty; }
+           none {
+               let tpt = csearch::get_field_type(tcx, class_id, id);
+               // ok b/c fields are monomorphic
+               // TODO: Comment might be a lie, what if it mentions
+               // class-bound ty params?
+               tcx.tcache.insert(id, tpt);
+               ret tpt.ty;
+           }
+        }
+    }
+}
+
 // Look up the list of item types for a given class
 // Fails if the id is not bound to a class.
-fn lookup_class_item_tys(cx: ctxt, did: ast::def_id) -> [@class_item_ty] {
+fn lookup_class_fields(cx: ctxt, did: ast::def_id) -> [field_ty] {
   if did.crate == ast::local_crate {
     alt cx.items.find(did.node) {
        some(ast_map::node_item(i,_)) {
          alt i.node {
            ast::item_class(_, items, _) {
-               class_item_tys(cx, items)
+               class_field_tys(items)
            }
            _ { cx.sess.bug("class ID bound to non-class"); }
          }
@@ -2451,27 +2474,19 @@ fn lookup_class_item_tys(cx: ctxt, did: ast::def_id) -> [@class_item_ty] {
     }
         }
   else {
-        ret csearch::get_class_items(cx, did);
+        ret csearch::get_class_fields(cx, did);
     }
 }
 
 // must be called after typechecking?
-fn class_item_tys(cx: ctxt, items: [@class_item]) -> [@class_item_ty] {
+fn class_field_tys(items: [@class_item]) -> [field_ty] {
     let rslt = [];
     for it in items {
        alt it.node.decl {
           instance_var(nm, _, _, id) {
-              rslt += [@{ident: nm, id: id,
-                        contents: var_ty(node_id_to_type(cx, id)) }];
+              rslt += [{ident: nm, id: ast_util::local_def(id)}];
           }
-          class_method(it) {
-              alt it.node {
-                 item_fn(dec, _, _) {
-                     rslt += [@{ident: it.ident, id: it.id,
-                                 contents: method_ty(dec)}];
-                 }
-                 _ { fail; /* TODO */ }
-               }
+          class_method(_) {
           }
        }
     }
@@ -2482,19 +2497,11 @@ fn class_item_tys(cx: ctxt, items: [@class_item]) -> [@class_item_ty] {
 // (as if the class was a record). trans uses this
 fn class_items_as_fields(cx:ctxt, did: ast::def_id) -> [field] {
     let rslt = [];
-    for ci in lookup_class_item_tys(cx, did) {
-       alt ci.contents {
-          var_ty(t) {
-             // consider all instance vars mutable, because the
-             // constructor may mutate all vars
-             rslt += [{ident: ci.ident, mt: {ty: t,
-                             mutbl: m_mutbl}}];
-          }
-         /* do nothing, since methods don't have a runtime
-          representation? */
-          method_ty(_) {
-          }
-       }
+    for f in lookup_class_fields(cx, did) {
+       // consider all instance vars mutable, because the
+       // constructor may mutate all vars
+      rslt += [{ident: f.ident, mt: {ty: lookup_field_type(cx, did, f.id),
+                  mutbl: m_mutbl}}];
     }
     rslt
 }
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 528e8fb9500..87bb55e1b76 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -1,7 +1,7 @@
 import result::result;
 import syntax::{ast, ast_util};
 import ast::spanned;
-import syntax::ast_util::{local_def, respan};
+import syntax::ast_util::{local_def, respan, split_class_items};
 import syntax::visit;
 import metadata::csearch;
 import driver::session::session;
@@ -11,7 +11,7 @@ import pat_util::*;
 import middle::ty;
 import middle::ty::{node_id_to_type, arg, block_ty,
                     expr_ty, field, node_type_table, mk_nil,
-                    ty_param_bounds_and_ty, lookup_class_item_tys};
+                    ty_param_bounds_and_ty, lookup_class_fields};
 import util::ppaux::ty_to_str;
 import std::smallintmap;
 import std::map::{hashmap, int_hash};
@@ -896,20 +896,38 @@ mod collect {
           }
         }
     }
-    fn convert_class_item(tcx: ty::ctxt, ci: ast::class_member) {
+    fn convert_class_item(tcx: ty::ctxt, v: ast_util::ivar) {
         /* we want to do something here, b/c within the
          scope of the class, it's ok to refer to fields &
         methods unqualified */
 
         /* they have these types *within the scope* of the
          class. outside the class, it's done with expr_field */
-        alt ci {
-         ast::instance_var(_,t,_,id) {
-             let tt = ast_ty_to_ty(tcx, m_collect, t);
-             write_ty(tcx, id, tt);
-         }
-         ast::class_method(it) { convert(tcx, it); }
-        }
+        let tt = ast_ty_to_ty(tcx, m_collect, v.ty);
+        #debug("convert_class_item: %s %?", v.ident, v.id);
+        write_ty(tcx, v.id, tt);
+    }
+    fn convert_methods(tcx: ty::ctxt, ms: [@ast::method],
+        i_bounds: @[ty::param_bounds], maybe_self: option<ty::t>)
+        -> [{mty: ty::method, id: ast::node_id, span: span}] {
+        let my_methods = [];
+        for m in ms {
+           alt maybe_self {
+              some(selfty) {
+                write_ty(tcx, m.self_id, selfty);
+              }
+              _ {}
+           }
+           let bounds = ty_param_bounds(tcx, m_collect, m.tps);
+           let mty = ty_of_method(tcx, m_collect, m);
+           my_methods += [{mty: mty, id: m.id, span: m.span}];
+           let fty = ty::mk_fn(tcx, mty.fty);
+           tcx.tcache.insert(local_def(m.id),
+                             {bounds: @(*i_bounds + *bounds),
+                                     ty: fty});
+           write_ty(tcx, m.id, fty);
+        }
+        my_methods
     }
     fn convert(tcx: ty::ctxt, it: @ast::item) {
         alt it.node {
@@ -922,22 +940,11 @@ mod collect {
           }
           ast::item_impl(tps, ifce, selfty, ms) {
             let i_bounds = ty_param_bounds(tcx, m_collect, tps);
-            let my_methods = [];
             let selfty = ast_ty_to_ty(tcx, m_collect, selfty);
             write_ty(tcx, it.id, selfty);
             tcx.tcache.insert(local_def(it.id), {bounds: i_bounds,
                                                  ty: selfty});
-            for m in ms {
-                write_ty(tcx, m.self_id, selfty);
-                let bounds = ty_param_bounds(tcx, m_collect, m.tps);
-                let mty = ty_of_method(tcx, m_collect, m);
-                my_methods += [{mty: mty, id: m.id, span: m.span}];
-                let fty = ty::mk_fn(tcx, mty.fty);
-                tcx.tcache.insert(local_def(m.id),
-                                     {bounds: @(*i_bounds + *bounds),
-                                      ty: fty});
-                write_ty(tcx, m.id, fty);
-            }
+            let my_methods = convert_methods(tcx, ms, i_bounds, some(selfty));
             alt ifce {
               some(t) {
                 let iface_ty = ast_ty_to_ty(tcx, m_collect, t);
@@ -1028,9 +1035,11 @@ mod collect {
                                    {bounds: tpt.bounds, ty: t_ctor});
               /* FIXME: check for proper public/privateness */
               // Write the type of each of the members
-              for m in members {
-                 convert_class_item(tcx, m.node.decl);
+              let (fields, methods) = split_class_items(members);
+              for f in fields {
+                 convert_class_item(tcx, f);
               }
+              convert_methods(tcx, methods, @[], none);
           }
           _ {
             // This call populates the type cache with the converted type
@@ -1732,8 +1741,10 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity,
         alt ccx.method_map.find(callee.id) {
           some(method_static(did)) {
             if did.crate == ast::local_crate {
-                alt check ccx.tcx.items.get(did.node) {
+                alt ccx.tcx.items.get(did.node) {
                   ast_map::node_method(m, _, _) { m.decl.purity }
+                  _ { ccx.tcx.sess.span_bug(sp,
+                             "Node not bound to a method") }
                 }
             } else {
                 csearch::lookup_method_purity(ccx.tcx.sess.cstore, did)
@@ -1834,6 +1845,43 @@ fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
     }
 }
 
+enum method_parent {
+    cls(ast::def_id),
+    an_iface(ast::def_id)
+}
+
+fn lookup_method_inner_(tcx: ty::ctxt, ms: [ty::method],
+    tps: [ty::t], parent: method_parent, name: ast::ident, sp: span)
+    -> 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 i = 0u;
+    for m in ms  {
+       if m.ident == name {
+          let fty = ty::mk_fn(tcx, {proto: ast::proto_box with m.fty});
+          if ty::type_has_vars(fty) {
+               tcx.sess.span_fatal(
+                    sp, "can not call a method that contains a \
+                                    self type through a boxed iface");
+          } else if (*m.tps).len() > 0u {
+                   tcx.sess.span_fatal(
+                        sp, "can not call a generic method through a \
+                                    boxed iface");
+          }
+          ret some({method_ty: fty,
+                          n_tps: vec::len(*m.tps),
+                          substs: tps,
+                          origin: alt parent {
+                                    cls(did) { method_static(did) }
+                                    an_iface(did) { method_iface(did, i) }
+                          },
+                      self_sub: none});
+       }
+       i += 1u;
+    }
+    ret none;
+}
+
 fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
                        name: ast::ident, ty: ty::t)
     -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
@@ -1871,26 +1919,17 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
         }
       }
       ty::ty_iface(did, tps) {
-        let i = 0u;
-        for m in *ty::iface_methods(tcx, did) {
-            if m.ident == name {
-                let fty = ty::mk_fn(tcx, {proto: ast::proto_box with m.fty});
-                if ty::type_has_vars(fty) {
-                    tcx.sess.span_fatal(
-                        expr.span, "can not call a method that contains a \
-                                    self type through a boxed iface");
-                } else if (*m.tps).len() > 0u {
-                    tcx.sess.span_fatal(
-                        expr.span, "can not call a generic method through a \
-                                    boxed iface");
-                }
-                ret some({method_ty: fty,
-                          n_tps: vec::len(*m.tps),
-                          substs: tps,
-                          origin: method_iface(did, i),
-                          self_sub: none});
-            }
-            i += 1u;
+        alt lookup_method_inner_(tcx, *ty::iface_methods(tcx, did), tps,
+                                 an_iface(did), name, expr.span) {
+           some(r) { ret some(r); }
+           none {  }
+        }
+      }
+      ty::ty_class(did, tps) {
+        alt lookup_method_inner_(tcx, *ty::iface_methods(tcx, did), tps,
+                                 cls(did), name, expr.span) {
+          some(r) { ret some(r); }
+          none    { }
         }
       }
       _ {}
@@ -1957,19 +1996,12 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
     result
 }
 
-// problem -- class_item_ty should really be only used for internal stuff.
-// or should have a privacy field.
-fn lookup_field_ty(cx: ty::ctxt, items:[@ty::class_item_ty],
-                   fieldname: ast::ident, sp: span)
-    -> ty::t {
-    for item in items {
-            #debug("%s $$$ %s", fieldname, item.ident);
-        alt item.contents {
-          ty::var_ty(t) if item.ident == fieldname { ret t; }
-          _ { }
-        }
-    }
-    cx.sess.span_fatal(sp, #fmt("unbound field %s", fieldname));
+// Only for fields! Returns <none> for methods>
+// FIXME: privacy flags
+fn lookup_field_ty(tcx: ty::ctxt, class_id: ast::def_id,
+  items:[ty::field_ty], fieldname: ast::ident) -> option<ty::t> {
+    option::map(vec::find(items, {|f| f.ident == fieldname}),
+                {|f| ty::lookup_field_type(tcx, class_id, f.id) })
 }
 
 /*
@@ -2053,6 +2085,7 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
 
 fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
                            expected: ty::t) -> bool {
+
     #debug("typechecking expr %s",
            syntax::print::pprust::expr_to_str(expr));
 
@@ -2191,10 +2224,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
     fn check_call_full(fcx: @fn_ctxt, sp: span, id: ast::node_id,
                        f: @ast::expr, args: [@ast::expr]) -> bool {
         let bot = check_call(fcx, sp, id, f, args);
-        /* here we're kind of hosed, as f can be any expr
-        need to restrict it to being an explicit expr_path if we're
-        inside a pure function, and need an environment mapping from
-        function name onto purity-designation */
+        /* need to restrict oper to being an explicit expr_path if we're
+        inside a pure function */
         require_pure_call(fcx.ccx, fcx.purity, f, sp);
 
         // Pull the return type out of the type of the function.
@@ -2774,13 +2805,19 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
           ty::ty_class(base_id, _params) {
               // (1) verify that the class id actually has a field called
               // field
-              let cls_items = lookup_class_item_tys(tcx, base_id);
-              let field_ty = lookup_field_ty(fcx.ccx.tcx, cls_items, field,
-                                             expr.span);
-              // (2) look up what field's type is, and return it
-              // FIXME: actually instantiate any type params
-              write_ty(tcx, id, field_ty);
-              handled = true;
+              #debug("class named %s", ty_to_str(tcx, base_t));
+              let cls_items = lookup_class_fields(tcx, base_id);
+              #debug("cls_items: %?", cls_items);
+              alt lookup_field_ty(tcx, base_id, cls_items, field) {
+                 some(field_ty) {
+                     #debug("a");
+                    // (2) look up what field's type is, and return it
+                    // FIXME: actually instantiate any type params
+                     write_ty(tcx, id, field_ty);
+                     handled = true;
+                 }
+                 none { #debug("b"); }
+              }
           }
           _ {}
         }
@@ -3226,8 +3263,9 @@ fn class_types(ccx: @crate_ctxt, members: [@ast::class_item]) -> class_map {
          ast::instance_var(_,t,_,id) {
            rslt.insert(id, ast_ty_to_ty(ccx.tcx, m_collect, t));
          }
-         ast::class_method(it) {
-             rslt.insert(it.id, ty_of_item(ccx.tcx, m_collect, it).ty);
+         ast::class_method(mth) {
+             rslt.insert(mth.id, ty::mk_fn(ccx.tcx,
+                   ty_of_method(ccx.tcx, m_collect, mth).fty));
          }
       }
     }
@@ -3239,7 +3277,7 @@ fn check_class_member(ccx: @crate_ctxt, cm: ast::class_member) {
       ast::instance_var(_,t,_,_) { // ??? Not sure
       }
       // not right yet -- need a scope
-      ast::class_method(i) { check_item(ccx, i); }
+      ast::class_method(m) { check_method(ccx, m); }
     }
 }
 
diff --git a/src/rustc/syntax/ast.rs b/src/rustc/syntax/ast.rs
index 43b0d5e0391..db0f6a56d80 100644
--- a/src/rustc/syntax/ast.rs
+++ b/src/rustc/syntax/ast.rs
@@ -659,10 +659,10 @@ type class_item = spanned<class_item_>;
 #[auto_serialize]
 enum class_member {
     instance_var(ident, @ty, class_mutability, node_id),
-    class_method(@item) // FIXME: methods aren't allowed to be
-    // type-parametric.
+    class_method(@method)
     // without constrained types, have to duplicate some stuff. or factor out
     // item to separate out things with type params?
+    // (FIXME) where do we enforce that type params is empty?
 }
 
 #[auto_serialize]
diff --git a/src/rustc/syntax/ast_util.rs b/src/rustc/syntax/ast_util.rs
index 1182a2c40c3..5625fecb953 100644
--- a/src/rustc/syntax/ast_util.rs
+++ b/src/rustc/syntax/ast_util.rs
@@ -433,6 +433,21 @@ pure fn class_item_ident(ci: @class_item) -> ident {
     }
 }
 
+type ivar = {ident: ident, ty: @ty, cm: class_mutability, id: node_id};
+
+fn split_class_items(cs: [@class_item]) -> ([ivar], [@method]) {
+    let vs = [], ms = [];
+    for c in cs {
+      alt c.node.decl {
+        instance_var(i, t, cm, id) {
+          vs += [{ident: i, ty: t, cm: cm, id: id}];
+        }
+        class_method(m) { ms += [m]; }
+      }
+    }
+    (vs, ms)
+}
+
 impl inlined_item_methods for inlined_item {
     fn ident() -> ident {
         alt self {
@@ -455,7 +470,6 @@ impl inlined_item_methods for inlined_item {
         }
     }
 }
-
 // Local Variables:
 // mode: rust
 // fill-column: 78;
diff --git a/src/rustc/syntax/fold.rs b/src/rustc/syntax/fold.rs
index 0a3e42aee34..0927c94887f 100644
--- a/src/rustc/syntax/fold.rs
+++ b/src/rustc/syntax/fold.rs
@@ -249,7 +249,7 @@ fn noop_fold_class_item(&&ci: @class_item, fld: ast_fold)
         instance_var(ident, t, cm, id) {
             instance_var(ident, fld.fold_ty(t), cm, id)
         }
-        class_method(i) { class_method(fld.fold_item(i)) }
+        class_method(m) { class_method(fld.fold_method(m)) }
          }},
        span: fld.new_span(ci.span)}
 }
@@ -656,8 +656,8 @@ fn make_fold(afp: ast_fold_precursor) -> ast_fold {
                instance_var(nm, f_ty(afp, f, t),
                                  mt, id)
            }
-           class_method(i) {
-               class_method(afp.fold_item(i, f))
+           class_method(m) {
+               class_method(afp.fold_method(m, f))
            }
             }}, span: afp.new_span(ci.span)}
     }
diff --git a/src/rustc/syntax/parse/parser.rs b/src/rustc/syntax/parse/parser.rs
index 06d59be0654..4fe7aade41c 100644
--- a/src/rustc/syntax/parse/parser.rs
+++ b/src/rustc/syntax/parse/parser.rs
@@ -1648,10 +1648,10 @@ fn parse_let(p: parser) -> @ast::decl {
     ret @spanned(lo, p.last_span.hi, ast::decl_local(locals));
 }
 
+/* assumes "let" token has already been consumed */
 fn parse_instance_var(p:parser) -> (ast::class_member, codemap::span) {
     let is_mutbl = ast::class_immutable;
     let lo = p.span.lo;
-    expect_word(p, "let");
     if eat_word(p, "mut") || eat_word(p, "mutable") {
             is_mutbl = ast::class_mutable;
     }
@@ -2104,15 +2104,14 @@ enum class_contents { ctor_decl(ast::fn_decl, ast::blk, codemap::span),
             expect(p, token::LBRACE);
             let results = [];
             while p.token != token::RBRACE {
-               alt parse_item(p, []) {
-                 some(i) {
-                     results += [(ast::class_method(i), i.span)];
-                 }
-                 _ {
-                     let a_var = parse_instance_var(p);
-                     expect(p, token::SEMI);
-                     results += [a_var];
-                 }
+               if eat_word(p, "let") {
+                  let a_var = parse_instance_var(p);
+                  expect(p, token::SEMI);
+                  results += [a_var];
+               }
+               else {
+                   let m = parse_method(p);
+                   results += [(ast::class_method(m), m.span)];
                }
             }
             p.bump();
@@ -2120,15 +2119,14 @@ enum class_contents { ctor_decl(ast::fn_decl, ast::blk, codemap::span),
     }
     else {
         // Probably need to parse attrs
-        alt parse_item(p, []) {
-         some(i) {
-             ret plain_decl(ast::class_method(i), i.span);
-         }
-         _ {
+        ret if eat_word(p, "let") {
              let (a_var, a_span) = parse_instance_var(p);
              expect(p, token::SEMI);
-             ret plain_decl(a_var, a_span);
-         }
+             plain_decl(a_var, a_span)
+        }
+        else {
+            let m = parse_method(p);
+            plain_decl(ast::class_method(m), m.span)
         }
     }
 }
diff --git a/src/rustc/syntax/print/pprust.rs b/src/rustc/syntax/print/pprust.rs
index 34d6d09b5ad..e10262117a4 100644
--- a/src/rustc/syntax/print/pprust.rs
+++ b/src/rustc/syntax/print/pprust.rs
@@ -526,8 +526,8 @@ fn print_item(s: ps, &&item: @ast::item) {
                     print_type(s, t);
                     word(s.s, ";");
                 }
-                ast::class_method(i) {
-                    print_item(s, i);
+                ast::class_method(m) {
+                    print_method(s, m);
                 }
              }
              alt ci.node.privacy {
@@ -555,12 +555,7 @@ fn print_item(s: ps, &&item: @ast::item) {
         space(s.s);
         bopen(s);
         for meth in methods {
-            hardbreak_if_not_bol(s);
-            maybe_print_comment(s, meth.span.lo);
-            print_outer_attributes(s, meth.attrs);
-            print_fn(s, meth.decl, meth.ident, meth.tps);
-            word(s.s, " ");
-            print_block_with_attrs(s, meth.body, meth.attrs);
+           print_method(s, meth);
         }
         bclose(s, item.span);
       }
@@ -621,6 +616,15 @@ fn print_ty_method(s: ps, m: ast::ty_method) {
     word(s.s, ";");
 }
 
+fn print_method(s: ps, meth: @ast::method) {
+    hardbreak_if_not_bol(s);
+    maybe_print_comment(s, meth.span.lo);
+    print_outer_attributes(s, meth.attrs);
+    print_fn(s, meth.decl, meth.ident, meth.tps);
+    word(s.s, " ");
+    print_block_with_attrs(s, meth.body, meth.attrs);
+}
+
 fn print_outer_attributes(s: ps, attrs: [ast::attribute]) {
     let count = 0;
     for attr: ast::attribute in attrs {
diff --git a/src/rustc/syntax/visit.rs b/src/rustc/syntax/visit.rs
index 5f92d533f32..c0b7eea6ace 100644
--- a/src/rustc/syntax/visit.rs
+++ b/src/rustc/syntax/visit.rs
@@ -157,8 +157,8 @@ fn visit_class_item<E>(_s: span, _p: privacy, cm: class_member,
         instance_var(ident, t, mt, id) {
             v.visit_ty(t, e, v);
         }
-        class_method(i) {
-            v.visit_item(i, e, v);
+        class_method(m) {
+            visit_method_helper(m, e, v);
         }
     }
 }
diff --git a/src/test/run-pass/classes-simple-method.rs b/src/test/run-pass/classes-simple-method.rs
index 5d2eaf9d37e..2c7c2c7c480 100644
--- a/src/test/run-pass/classes-simple-method.rs
+++ b/src/test/run-pass/classes-simple-method.rs
@@ -8,7 +8,11 @@ class cat {
 
   new(in_x : uint, in_y : int) { meows = in_x; how_hungry = in_y; }
 
-  fn speak() { fail; }
+  fn speak() {}
+  /*
+  fn speak() { meows += 1u; }
+  fn meow_count() -> uint { meows }
+  */
 }
 
 fn main() {
@@ -16,4 +20,6 @@ fn main() {
   let kitty = cat(1000u, 2);
   assert(nyan.how_hungry == 99);
   assert(kitty.how_hungry == 2);
+  nyan.speak();
+  //  assert(nyan.meow_count() == 53u);
 }