about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/comp/metadata/tydecode.rs7
-rw-r--r--src/comp/metadata/tyencode.rs5
-rw-r--r--src/comp/middle/resolve.rs11
-rw-r--r--src/comp/middle/shape.rs7
-rw-r--r--src/comp/middle/trans/base.rs5
-rw-r--r--src/comp/middle/trans/impl.rs19
-rw-r--r--src/comp/middle/ty.rs63
-rw-r--r--src/comp/middle/typeck.rs268
-rw-r--r--src/comp/syntax/fold.rs4
-rw-r--r--src/rustdoc/tystr_pass.rs2
10 files changed, 242 insertions, 149 deletions
diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs
index dc7496dddb3..680129aa778 100644
--- a/src/comp/metadata/tydecode.rs
+++ b/src/comp/metadata/tydecode.rs
@@ -216,6 +216,13 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
         let did = parse_def(st, conv);
         ret ty::mk_param(st.tcx, parse_int(st) as uint, did);
       }
+      's' {
+        assert next(st) as char == '[';
+        let params = [];
+        while peek(st) as char != ']' { params += [parse_ty(st, conv)]; }
+        st.pos += 1u;
+        ret ty::mk_self(st.tcx, params);
+      }
       '@' { ret ty::mk_box(st.tcx, parse_mt(st, conv)); }
       '~' { ret ty::mk_uniq(st.tcx, parse_mt(st, conv)); }
       '*' { ret ty::mk_ptr(st.tcx, parse_mt(st, conv)); }
diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs
index a9baa4f7470..9570669d203 100644
--- a/src/comp/metadata/tyencode.rs
+++ b/src/comp/metadata/tyencode.rs
@@ -169,6 +169,11 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
         w.write_char('|');
         w.write_str(uint::str(id));
       }
+      ty::ty_self(tps) {
+        w.write_str("s[");
+        for t in tps { enc_ty(w, cx, t); }
+        w.write_char(']');
+      }
       ty::ty_type { w.write_char('Y'); }
       ty::ty_send_type { w.write_char('y'); }
       ty::ty_opaque_closure_ptr(ty::ck_block) { w.write_str("C&"); }
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 2ba68b927f0..043e28b57c0 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -888,10 +888,17 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
               ast::item_impl(tps, _, _, _) {
                 if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
               }
-              ast::item_iface(tps, _) | ast::item_enum(_, tps) |
-              ast::item_ty(_, tps) {
+              ast::item_enum(_, tps) | ast::item_ty(_, tps) {
                 if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
               }
+              ast::item_iface(tps, _) {
+                if ns == ns_type {
+                    if name == "self" {
+                        ret some(def_self(local_def(it.id)));
+                    }
+                    ret lookup_in_ty_params(e, name, tps);
+                }
+              }
               ast::item_mod(_) {
                 ret lookup_in_local_mod(e, it.id, sp, name, ns, inside);
               }
diff --git a/src/comp/middle/shape.rs b/src/comp/middle/shape.rs
index 500a8591516..6d94552db7a 100644
--- a/src/comp/middle/shape.rs
+++ b/src/comp/middle/shape.rs
@@ -421,9 +421,6 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
         add_substr(s, shape_of(ccx, subt, ty_param_map));
 
       }
-      ty::ty_var(n) {
-        fail "shape_of ty_var";
-      }
       ty::ty_param(n, _) {
         // Find the type parameter in the parameter list.
         alt vec::position_elt(ty_param_map, n) {
@@ -450,8 +447,8 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
       ty::ty_constr(inner_t, _) {
         s += shape_of(ccx, inner_t, ty_param_map);
       }
-      ty::ty_named(_, _) {
-        ccx.tcx.sess.bug("shape_of: shouldn't see a ty_named");
+      ty::ty_var(_) | ty::ty_named(_, _) | ty::ty_self(_) {
+        ccx.tcx.sess.bug("shape_of: unexpected type struct found");
       }
     }
 
diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs
index 37e410e9d5c..6868c233cff 100644
--- a/src/comp/middle/trans/base.rs
+++ b/src/comp/middle/trans/base.rs
@@ -5315,7 +5315,10 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
         impl::trans_impl_vtable(ccx, item_path(ccx, it), i_did, ms, tps, it);
       }
       ast::item_iface(_, _) {
-        impl::trans_iface_vtable(ccx, item_path(ccx, it), it);
+        if !vec::any(*ty::iface_methods(ccx.tcx, local_def(it.id)), {|m|
+            ty::type_contains_vars(ccx.tcx, ty::mk_fn(ccx.tcx, m.fty))}) {
+            impl::trans_iface_vtable(ccx, item_path(ccx, it), it);
+        }
       }
       _ { }
     }
diff --git a/src/comp/middle/trans/impl.rs b/src/comp/middle/trans/impl.rs
index 18ee215b2dc..c2f0d655da0 100644
--- a/src/comp/middle/trans/impl.rs
+++ b/src/comp/middle/trans/impl.rs
@@ -94,10 +94,9 @@ fn trans_static_callee(bcx: @block_ctxt, callee_id: ast::node_id,
     {env: self_env(val) with lval_static_fn(bcx, did, callee_id)}
 }
 
-fn wrapper_fn_ty(ccx: @crate_ctxt, dict_ty: TypeRef, m: ty::method)
-    -> {ty: ty::t, llty: TypeRef} {
-    let fty = ty::mk_fn(ccx.tcx, m.fty);
-    let bare_fn_ty = type_of_fn_from_ty(ccx, fty, *m.tps);
+fn wrapper_fn_ty(ccx: @crate_ctxt, dict_ty: TypeRef, fty: ty::t,
+                 tps: @[ty::param_bounds]) -> {ty: ty::t, llty: TypeRef} {
+    let bare_fn_ty = type_of_fn_from_ty(ccx, fty, *tps);
     let {inputs, output} = llfn_arg_tys(bare_fn_ty);
     {ty: fty, llty: T_fn([dict_ty] + inputs, output)}
 }
@@ -107,7 +106,9 @@ fn trans_vtable_callee(bcx: @block_ctxt, self: ValueRef, dict: ValueRef,
                        n_method: uint) -> lval_maybe_callee {
     let bcx = bcx, ccx = bcx_ccx(bcx), tcx = ccx.tcx;
     let method = ty::iface_methods(tcx, iface_id)[n_method];
-    let {ty: fty, llty: llfty} = wrapper_fn_ty(ccx, val_ty(dict), method);
+    let {ty: fty, llty: llfty} =
+        wrapper_fn_ty(ccx, val_ty(dict), ty::node_id_to_type(tcx, callee_id),
+                      method.tps);
     let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
                              T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
     let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
@@ -266,7 +267,8 @@ fn trans_impl_vtable(ccx: @crate_ctxt, pt: path,
 
 fn trans_iface_wrapper(ccx: @crate_ctxt, pt: path, m: ty::method,
                        n: uint) -> ValueRef {
-    let {llty: llfty, _} = wrapper_fn_ty(ccx, T_ptr(T_i8()), m);
+    let {llty: llfty, _} = wrapper_fn_ty(ccx, T_ptr(T_i8()),
+                                         ty::mk_fn(ccx.tcx, m.fty), m.tps);
     trans_wrapper(ccx, pt, llfty, {|llfn, bcx|
         let self = Load(bcx, PointerCast(bcx,
                                          LLVMGetParam(llfn, 2u as c_uint),
@@ -358,10 +360,7 @@ fn dict_id(tcx: ty::ctxt, origin: typeck::dict_origin) -> dict_id {
                     d_params += [dict_param_dict(dict_id(tcx, origs[orig]))];
                     orig += 1u;
                   }
-                  _ {
-                    tcx.sess.bug("Someone forgot to document an invariant in \
-                      dict_id");
-                  }
+                  _ {}
                 }
             }
         }
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 0826eda4cf3..0f03d273b4c 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -80,6 +80,7 @@ export mk_send_type;
 export mk_uint;
 export mk_uniq;
 export mk_var;
+export mk_self;
 export mk_opaque_closure_ptr;
 export mk_named;
 export gen_ty;
@@ -126,6 +127,7 @@ export ty_send_type;
 export ty_uint;
 export ty_uniq;
 export ty_var;
+export ty_self;
 export ty_named;
 export same_type;
 export ty_var_id;
@@ -266,9 +268,10 @@ enum sty {
     ty_iface(def_id, [t]),
     ty_res(def_id, t, [t]),
     ty_tup([t]),
-    ty_var(int), // type variable
 
-    ty_param(uint, def_id), // fn/enum type param
+    ty_var(int), // type variable during typechecking
+    ty_param(uint, def_id), // type parameter
+    ty_self([t]), // interface method self type
 
     ty_type, // type_desc*
     ty_send_type, // type_desc* that has been cloned into exchange heap
@@ -324,45 +327,25 @@ type ty_param_bounds_and_ty = {bounds: @[param_bounds], ty: t};
 type type_cache = hashmap<ast::def_id, ty_param_bounds_and_ty>;
 
 const idx_nil: uint = 0u;
-
 const idx_bool: uint = 1u;
-
 const idx_int: uint = 2u;
-
 const idx_float: uint = 3u;
-
 const idx_uint: uint = 4u;
-
 const idx_i8: uint = 5u;
-
 const idx_i16: uint = 6u;
-
 const idx_i32: uint = 7u;
-
 const idx_i64: uint = 8u;
-
 const idx_u8: uint = 9u;
-
 const idx_u16: uint = 10u;
-
 const idx_u32: uint = 11u;
-
 const idx_u64: uint = 12u;
-
 const idx_f32: uint = 13u;
-
 const idx_f64: uint = 14u;
-
 const idx_char: uint = 15u;
-
 const idx_str: uint = 16u;
-
 const idx_type: uint = 17u;
-
 const idx_send_type: uint = 18u;
-
 const idx_bot: uint = 19u;
-
 const idx_first_others: uint = 20u;
 
 type type_store = interner::interner<@raw_t>;
@@ -462,7 +445,7 @@ fn mk_raw_ty(cx: ctxt, st: sty) -> @raw_t {
       ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
       ty_str | ty_type | ty_send_type | ty_opaque_closure_ptr(_) {}
       ty_param(_, _) { has_params = true; }
-      ty_var(_) { has_vars = true; }
+      ty_var(_) | ty_self(_) { has_vars = true; }
       ty_enum(_, tys) | ty_iface(_, tys) {
         for tt: t in tys { derive_flags_t(cx, has_params, has_vars, tt); }
       }
@@ -598,6 +581,8 @@ fn mk_res(cx: ctxt, did: ast::def_id, inner: t, tps: [t]) -> t {
 
 fn mk_var(cx: ctxt, v: int) -> t { ret gen_ty(cx, ty_var(v)); }
 
+fn mk_self(cx: ctxt, tps: [t]) -> t { ret gen_ty(cx, ty_self(tps)); }
+
 fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
     ret gen_ty(cx, ty_param(n, k));
 }
@@ -653,7 +638,6 @@ pure fn ty_name(cx: ctxt, typ: t) -> option<@str> {
 }
 
 fn default_arg_mode_for_ty(tcx: ty::ctxt, ty: ty::t) -> ast::rmode {
-    assert !ty::type_contains_vars(tcx, ty);
     if ty::type_is_immediate(tcx, ty) { ast::by_val }
     else { ast::by_ref }
 }
@@ -664,7 +648,7 @@ fn walk_ty(cx: ctxt, ty: t, f: fn(t)) {
       ty_str | ty_send_type | ty_type |
       ty_opaque_closure_ptr(_) | ty_var(_) | ty_param(_, _) {}
       ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, tm.ty, f); }
-      ty_enum(_, subtys) | ty_iface(_, subtys) {
+      ty_enum(_, subtys) | ty_iface(_, subtys) | ty_self(subtys) {
         for subty: t in subtys { walk_ty(cx, subty, f); }
       }
       ty_rec(fields) {
@@ -728,6 +712,9 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
       ty_iface(did, subtys) {
         ty = mk_iface(cx, did, vec::map(subtys, {|t| fold_ty(cx, fld, t) }));
       }
+      ty_self(subtys) {
+        ty = mk_self(cx, vec::map(subtys, {|t| fold_ty(cx, fld, t) }));
+      }
       ty_rec(fields) {
         let new_fields: [field] = [];
         for fl: field in fields {
@@ -1189,15 +1176,9 @@ fn type_is_pod(cx: ctxt, ty: t) -> bool {
         result = type_is_pod(cx, substitute_type_params(cx, tps, inner));
       }
       ty_constr(subt, _) { result = type_is_pod(cx, subt); }
-      ty_var(_) {
-          cx.sess.bug("ty_var in type_is_pod");
-      }
       ty_param(_, _) { result = false; }
       ty_opaque_closure_ptr(_) { result = true; }
-      ty_named(_,_) {
-          cx.sess.bug("ty_named in type_is_pod");
-      }
-
+      _ { cx.sess.bug("unexpected type in type_is_pod"); }
     }
 
     ret result;
@@ -1352,6 +1333,11 @@ fn hash_type_structure(st: sty) -> uint {
       ty_fn(f) { ret hash_fn(27u, f.inputs, f.output); }
       ty_var(v) { ret hash_uint(30u, v as uint); }
       ty_param(pid, _) { ret hash_uint(31u, pid); }
+      ty_self(ts) {
+        let h = 28u;
+        for t in ts { h += (h << 5u) + t; }
+        ret h;
+      }
       ty_type { ret 32u; }
       ty_bot { ret 34u; }
       ty_ptr(mt) { ret hash_subty(35u, mt.ty); }
@@ -2548,19 +2534,8 @@ fn type_err_to_str(err: ty::type_err) -> str {
 // Replaces type parameters in the given type using the given list of
 // substitions.
 fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t {
-   if !type_contains_params(cx, typ) { ret typ; }
     // Precondition? idx < vec::len(substs)
-    fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, _did: def_id)
-        -> t {
-        if idx < vec::len(*substs) {
-            ret substs[idx];
-        }
-        else {
-            fail #fmt("Internal error in substituter (substitute_type_params)\
-             %u %u", vec::len(*substs), idx);
-        }
-    }
-    ret fold_ty(cx, fm_param(bind substituter(cx, @substs, _, _)), typ);
+    fold_ty(cx, fm_param({|idx, _id| substs[idx]}), typ)
 }
 
 fn def_has_ty_params(def: ast::def) -> bool {
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 50f5dd21007..adc276ee335 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -44,9 +44,7 @@ type dict_map = hashmap<ast::node_id, dict_res>;
 type ty_table = hashmap<ast::def_id, ty::t>;
 
 // Used for typechecking the methods of an impl
-enum self_info {
-    self_impl(ty::t),
-}
+enum self_info { self_impl(ty::t) }
 
 type crate_ctxt = {mutable self_infos: [self_info],
                    impl_map: resolve::impl_map,
@@ -118,11 +116,6 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
         let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
         ret {bounds: @[], ty: typ};
       }
-      ast::def_mod(_) {
-        // Hopefully part of a path.
-        // TODO: return a type that's more poisonous, perhaps?
-        ret {bounds: @[], ty: ty::mk_nil(fcx.ccx.tcx)};
-      }
       ast::def_ty(_) {
         fcx.ccx.tcx.sess.span_fatal(sp, "expected value but found type");
       }
@@ -317,19 +310,34 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
         typ = ty::mk_fn(tcx, ty_of_fn_decl(tcx, mode, proto, decl));
       }
       ast::ty_path(path, id) {
-        alt tcx.def_map.find(id) {
-          some(ast::def_ty(id)) {
+        alt tcx.def_map.get(id) {
+          ast::def_ty(id) {
             typ = instantiate(tcx, ast_ty.span, mode, id, path.node.types);
           }
-          some(ast::def_ty_param(id, n)) {
+          ast::def_ty_param(id, n) {
+            if vec::len(path.node.types) > 0u {
+                tcx.sess.span_err(ast_ty.span, "provided type parameters to \
+                                                a type parameter");
+            }
             typ = ty::mk_param(tcx, n, id);
           }
-          some(_) {
-            tcx.sess.span_fatal(ast_ty.span,
-                                "found type name used as a variable");
+          ast::def_self(iface_id) {
+            alt tcx.items.get(iface_id.node) {
+              ast_map::node_item(@{node: ast::item_iface(tps, _), _}, _) {
+                if vec::len(tps) != vec::len(path.node.types) {
+                    tcx.sess.span_err(ast_ty.span, "incorrect number of type \
+                                                    parameter to self type");
+                }
+                typ = ty::mk_self(tcx, vec::map(path.node.types, {|ast_ty|
+                    ast_ty_to_ty(tcx, mode, ast_ty)
+                }));
+              }
+              _ { fail; }
+            }
           }
           _ {
-            tcx.sess.span_fatal(ast_ty.span, "internal error in instantiate");
+            tcx.sess.span_fatal(ast_ty.span,
+                                "found type name used as a variable");
           }
         }
       }
@@ -588,14 +596,17 @@ fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param])
 }
 
 fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
-                       impl_tps: uint, if_m: ty::method, substs: [ty::t]) {
+                       impl_tps: uint, if_m: ty::method, substs: [ty::t],
+                       self_ty: ty::t) -> ty::t {
     if impl_m.tps != if_m.tps {
         tcx.sess.span_err(sp, "method `" + if_m.ident +
                           "` has an incompatible set of type parameters");
+        ty::mk_fn(tcx, impl_m.fty)
     } else {
         let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f|
             alt ty::struct(tcx, f.ty) {
-              ty::ty_param(0u, _) {
+              ty::ty_param(_, _) | ty::ty_self(_)
+              if alt i.mode { ast::infer(_) { true } _ { false } } {
                 {mode: ast::expl(ast::by_ref) with i}
               }
               _ { i }
@@ -606,17 +617,79 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
         let substs = substs + vec::init_fn(vec::len(*if_m.tps), {|i|
             ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0})
         });
-        let if_fty = ty::substitute_type_params(tcx, substs,
-                                                ty::mk_fn(tcx, if_m.fty));
+        let if_fty = ty::mk_fn(tcx, if_m.fty);
+        if_fty = ty::substitute_type_params(tcx, substs, if_fty);
+        if ty::type_contains_vars(tcx, if_fty) {
+            if_fty = fixup_self_in_method_ty(tcx, if_fty, substs,
+                                             self_full(self_ty, impl_tps));
+        }
         alt ty::unify::unify(impl_fty, if_fty, ty::unify::precise, tcx) {
           ty::unify::ures_err(err) {
             tcx.sess.span_err(sp, "method `" + if_m.ident +
                               "` has an incompatible type: " +
                               ty::type_err_to_str(err));
-          }
-          _ {}
-        }
-    }
+            impl_fty
+          }
+          ty::unify::ures_ok(tp) { tp }
+        }
+    }
+}
+
+enum self_subst { self_param(ty::t, @fn_ctxt, span), self_full(ty::t, uint) }
+
+// Mangles an iface method ty to make its self type conform to the self type
+// of a specific impl or bounded type parameter. This is rather involved
+// because the type parameters of ifaces and impls are not required to line up
+// (an impl can have less or more parameters than the iface it implements), so
+// some mangling of the substituted types is required.
+fn fixup_self_in_method_ty(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t],
+                           self: self_subst) -> ty::t {
+    if ty::type_contains_vars(cx, mty) {
+        ty::fold_ty(cx, ty::fm_general(fn@(t: ty::t) -> ty::t {
+            alt ty::struct(cx, t) {
+              ty::ty_self(tps) {
+                if vec::len(tps) > 0u {
+                    // Move the substs into the type param system of the
+                    // context.
+                    let substs = vec::map(tps, {|t|
+                        let f = fixup_self_in_method_ty(cx, t, m_substs,
+                                                        self);
+                        ty::substitute_type_params(cx, m_substs, f)
+                    });
+                    alt self {
+                      self_param(t, fcx, sp) {
+                        // Simply ensure that the type parameters for the self
+                        // type match the context.
+                        vec::iter2(substs, m_substs) {|s, ms|
+                            demand::simple(fcx, sp, s, ms);
+                        }
+                        t
+                      }
+                      self_full(selfty, impl_n_tps) {
+                        // Add extra substs for impl type parameters.
+                        while vec::len(substs) < impl_n_tps {
+                            substs += [ty::mk_param(cx, vec::len(substs),
+                                                    {crate: 0, node: 0})];
+                        }
+                        // And for method type parameters.
+                        let method_n_tps =
+                            (vec::len(m_substs) - vec::len(tps)) as int;
+                        if method_n_tps > 0 {
+                            substs += vec::tail_n(m_substs, vec::len(m_substs)
+                                                  - (method_n_tps as uint));
+                        }
+                        // And then instantiate the self type using all those.
+                        ty::substitute_type_params(cx, substs, selfty)
+                      }
+                    }
+                } else {
+                    alt self { self_param(t, _, _) | self_full(t, _) { t } }
+                }
+              }
+              _ { t }
+            }
+        }), mty)
+    } else { mty }
 }
 
 // Item collection - a pair of bootstrap passes:
@@ -682,15 +755,15 @@ mod collect {
             for m in ms {
                 let bounds = ty_param_bounds(cx.tcx, m_collect, m.tps);
                 let mty = ty_of_method(cx.tcx, m_collect, m);
-                my_methods += [mty];
+                my_methods += [{mty: mty, id: m.id, span: m.span}];
                 let fty = ty::mk_fn(cx.tcx, mty.fty);
                 cx.tcx.tcache.insert(local_def(m.id),
                                      {bounds: @(*i_bounds + *bounds),
                                       ty: fty});
                 write_ty(cx.tcx, m.id, fty);
             }
-            write_ty(cx.tcx, it.id, ast_ty_to_ty(cx.tcx, m_collect,
-                                                       selfty));
+            let selfty = ast_ty_to_ty(cx.tcx, m_collect, selfty);
+            write_ty(cx.tcx, it.id, selfty);
             alt ifce {
               some(t) {
                 let iface_ty = ast_ty_to_ty(cx.tcx, m_collect, t);
@@ -700,10 +773,18 @@ mod collect {
                   ty::ty_iface(did, tys) {
                     for if_m in *ty::iface_methods(cx.tcx, did) {
                         alt vec::find(my_methods,
-                                      {|m| if_m.ident == m.ident}) {
-                          some(m) {
-                            compare_impl_method(cx.tcx, t.span, m,
-                                                vec::len(tps), if_m, tys);
+                                      {|m| if_m.ident == m.mty.ident}) {
+                          some({mty: m, id, span}) {
+                            let mt = compare_impl_method(
+                                cx.tcx, span, m, vec::len(tps), if_m, tys,
+                                selfty);
+                            let old = cx.tcx.tcache.get(local_def(id));
+                            if old.ty != mt {
+                                cx.tcx.tcache.insert(local_def(id),
+                                                     {bounds: old.bounds,
+                                                     ty: mt});
+                                write_ty(cx.tcx, id, mt);
+                            }
                           }
                           none {
                             cx.tcx.sess.span_err(t.span, "missing method `" +
@@ -1459,12 +1540,54 @@ fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} {
     }
 }
 
-fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
-                 name: ast::ident, ty: ty::t, sp: span)
-    -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
-                  origin: method_origin}> {
-    let tcx = fcx.ccx.tcx;
+fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
+                 name: ast::ident, ty: ty::t, tps: [ty::t])
+    -> option::t<method_origin> {
+    alt lookup_method_inner(fcx, expr, name, ty) {
+      some({method_ty: fty, n_tps: method_n_tps, substs, origin, self_sub}) {
+        let tcx = fcx.ccx.tcx;
+        let substs = substs, n_tps = vec::len(substs), n_tys = vec::len(tps);
+        let has_self = ty::type_contains_params(tcx, fty);
+        if method_n_tps + n_tps > 0u {
+            if n_tys > 0u {
+                if n_tys != method_n_tps {
+                    tcx.sess.span_fatal
+                        (expr.span, "incorrect number of type \
+                                     parameters given for this method");
+
+                }
+                substs += tps;
+            } else {
+                substs += vec::init_fn(method_n_tps, {|_i|
+                    ty::mk_var(tcx, next_ty_var_id(fcx))
+                });
+            };
+            write_ty_substs(tcx, node_id, fty, substs);
+        } else if n_tys > 0u {
+            tcx.sess.span_fatal(expr.span,
+                                "this method does not take type \
+                                 parameters");
+        } else {
+            write_ty(tcx, node_id, fty);
+        }
+        if has_self && !option::is_none(self_sub) {
+            let fty = ty::node_id_to_type(tcx, node_id);
+            fty = fixup_self_in_method_ty(
+                tcx, fty, substs, option::get(self_sub));
+            write_ty(tcx, node_id, fty);
+        }
+        some(origin)
+      }
+      none { none }
+    }
+}
 
+fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
+                       name: ast::ident, ty: ty::t)
+    -> option::t<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
+                  origin: method_origin,
+                  self_sub: option::t<self_subst>}> {
+    let tcx = fcx.ccx.tcx;
     // First, see whether this is an interface-bounded parameter
     alt ty::struct(tcx, ty) {
       ty::ty_param(n, did) {
@@ -1473,11 +1596,8 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
             alt bound {
               ty::bound_iface(t) {
                 let (iid, tps) = alt ty::struct(tcx, t) {
-                    ty::ty_iface(i, tps) { (i, tps) }
-                    _ {
-                        tcx.sess.span_bug(sp, "Undocument invariant in \
-                          lookup_method");
-                    }
+                  ty::ty_iface(i, tps) { (i, tps) }
+                  _ { fail; }
                 };
                 let ifce_methods = ty::iface_methods(tcx, iid);
                 alt vec::position(*ifce_methods, {|m| m.ident == name}) {
@@ -1486,7 +1606,9 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
                     ret some({method_ty: ty::mk_fn(tcx, m.fty),
                               n_tps: vec::len(*m.tps),
                               substs: tps,
-                              origin: method_param(iid, pos, n, bound_n)});
+                              origin: method_param(iid, pos, n, bound_n),
+                              self_sub: some(self_param(ty, fcx, expr.span))
+                             });
                   }
                   _ {}
                 }
@@ -1501,10 +1623,17 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
         let i = 0u;
         for m in *ty::iface_methods(tcx, did) {
             if m.ident == name {
-                ret some({method_ty: ty::mk_fn(tcx, m.fty),
+                let fty = ty::mk_fn(tcx, m.fty);
+                if ty::type_contains_vars(tcx, fty) {
+                    tcx.sess.span_fatal(
+                        expr.span, "can not call a method that contains a \
+                                    self type through a boxed iface");
+                }
+                ret some({method_ty: fty,
                           n_tps: vec::len(*m.tps),
                           substs: tps,
-                          origin: method_iface(i)});
+                          origin: method_iface(i),
+                          self_sub: none});
             }
             i += 1u;
         }
@@ -1527,7 +1656,7 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
     }
 
     let result = none;
-    std::list::iter(isc) {|impls|
+    std::list::iter(fcx.ccx.impl_map.get(expr.id)) {|impls|
         if option::is_some(result) { ret; }
         for @{did, methods, _} in *impls {
             alt vec::find(methods, {|m| m.ident == name}) {
@@ -1541,13 +1670,14 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
                     if option::is_some(result) {
                         // FIXME[impl] score specificity to resolve ambiguity?
                         tcx.sess.span_err(
-                            sp, "multiple applicable methods in scope");
+                           expr.span, "multiple applicable methods in scope");
                     } else {
                         result = some({
                             method_ty: ty_from_did(tcx, m.did),
                             n_tps: m.n_tps,
                             substs: vars,
-                            origin: method_static(m.did)
+                            origin: method_static(m.did),
+                            self_sub: none
                         });
                     }
                   }
@@ -1763,13 +1893,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         }
     }
     fn lookup_op_method(fcx: @fn_ctxt, op_ex: @ast::expr, self_t: ty::t,
-                        opname: str,
-                        args: [option<@ast::expr>]) -> option<ty::t> {
-        let isc = fcx.ccx.impl_map.get(op_ex.id);
-        alt lookup_method(fcx, isc, opname, self_t, op_ex.span) {
-          some({method_ty, n_tps: 0u, substs, origin}) {
-            let callee_id = ast_util::op_expr_callee_id(op_ex);
-            write_ty_substs(fcx.ccx.tcx, callee_id, method_ty, substs);
+                        opname: str, args: [option::t<@ast::expr>])
+        -> option::t<ty::t> {
+        let callee_id = ast_util::op_expr_callee_id(op_ex);
+        alt lookup_method(fcx, op_ex, callee_id, opname, self_t, []) {
+          some(origin) {
+            let method_ty = ty::node_id_to_type(fcx.ccx.tcx, callee_id);
             check_call_or_bind(fcx, op_ex.span, method_ty, args);
             fcx.ccx.method_map.insert(op_ex.id, origin);
             some(ty::ty_fn_ret(fcx.ccx.tcx, method_ty))
@@ -2235,36 +2364,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
           _ {}
         }
         if !handled {
-            let iscope = fcx.ccx.impl_map.get(expr.id);
-            alt lookup_method(fcx, iscope, field, expr_t, expr.span) {
-              some({method_ty: fty, n_tps: method_n_tps, substs, origin}) {
-                let substs = substs, n_tps = vec::len(substs);
-                if method_n_tps + n_tps > 0u {
-                    if n_tys > 0u {
-                        if n_tys != method_n_tps {
-                            tcx.sess.span_fatal
-                                (expr.span, "incorrect number of type \
-                                           parameters given for this method");
-
-                        }
-                        for ty in tys {
-                            substs += [ast_ty_to_ty_crate(fcx.ccx, ty)];
-                        }
-                    } else {
-                        let i = 0u;
-                        while i < method_n_tps {
-                            substs += [ty::mk_var(tcx, next_ty_var_id(fcx))];
-                            i += 1u;
-                        }
-                    }
-                    write_ty_substs(fcx.ccx.tcx, id, fty, substs);
-                } else if n_tys > 0u {
-                    tcx.sess.span_fatal(expr.span,
-                                        "this method does not take type \
-                                         parameters");
-                } else {
-                    write_ty(tcx, id, fty);
-                }
+            let tps = vec::map(tys, {|ty| ast_ty_to_ty_crate(fcx.ccx, ty)});
+            alt lookup_method(fcx, expr, expr.id, field, expr_t, tps) {
+              some(origin) {
                 fcx.ccx.method_map.insert(id, origin);
               }
               none {
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index 24c0a7446d4..6402571eda5 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -259,9 +259,7 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
             item_impl(tps, option::map(ifce, fld.fold_ty), fld.fold_ty(ty),
                       vec::map(methods, fld.fold_method))
           }
-          item_iface(tps, methods) {
-            item_iface(tps, methods)
-          }
+          item_iface(tps, methods) { item_iface(tps, methods) }
           item_res(decl, typms, body, did, cid) {
             item_res(fold_fn_decl(decl, fld), typms, fld.fold_block(body),
                      did, cid)
diff --git a/src/rustdoc/tystr_pass.rs b/src/rustdoc/tystr_pass.rs
index 58cbff8edb2..99137629db6 100644
--- a/src/rustdoc/tystr_pass.rs
+++ b/src/rustdoc/tystr_pass.rs
@@ -579,4 +579,4 @@ mod test {
         let doc = extract::from_srv(srv, "");
         run(srv, doc)
     }
-}
\ No newline at end of file
+}