about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-04-24 15:52:52 -0700
committerNiko Matsakis <niko@alum.mit.edu>2012-04-25 19:26:56 -0700
commit825fd1808e2ac8763d16940531f037c9b387c871 (patch)
tree493678053820169e7619bf741fa18fb3dbf72420
parent458d2ff067261ab646d914123f9c9c496cd612ae (diff)
lots of work to make iface/impls parameterized by regions
- paths can now take region parameters, replacing the dirty hack
  I was doing before of abusing vstores.  vstores are now a bit
  of a hack though.

- fix various small bugs:
  - we never checked that iface types were compatible when casting
    to an iface with `as`
  - we allowed nonsense like int<int>
  - and more! (actually that may be it)
-rw-r--r--src/librustsyntax/ast.rs14
-rw-r--r--src/librustsyntax/ast_util.rs3
-rw-r--r--src/librustsyntax/ext/auto_serialize.rs7
-rw-r--r--src/librustsyntax/ext/build.rs3
-rw-r--r--src/librustsyntax/ext/concat_idents.rs2
-rw-r--r--src/librustsyntax/ext/simplext.rs4
-rw-r--r--src/librustsyntax/fold.rs15
-rw-r--r--src/librustsyntax/parse/parser.rs242
-rw-r--r--src/librustsyntax/print/pprust.rs53
-rw-r--r--src/librustsyntax/visit.rs4
-rw-r--r--src/rustc/front/test.rs2
-rw-r--r--src/rustc/metadata/encoder.rs10
-rw-r--r--src/rustc/metadata/tydecode.rs21
-rw-r--r--src/rustc/metadata/tyencode.rs8
-rw-r--r--src/rustc/middle/ast_map.rs2
-rw-r--r--src/rustc/middle/infer.rs12
-rw-r--r--src/rustc/middle/resolve.rs47
-rw-r--r--src/rustc/middle/trans/base.rs2
-rw-r--r--src/rustc/middle/trans/impl.rs2
-rw-r--r--src/rustc/middle/trans/reachable.rs6
-rw-r--r--src/rustc/middle/tstate/pre_post_conditions.rs4
-rw-r--r--src/rustc/middle/ty.rs51
-rw-r--r--src/rustc/middle/typeck.rs683
-rw-r--r--src/rustc/util/ppaux.rs14
-rw-r--r--src/rustdoc/attr_pass.rs4
-rw-r--r--src/rustdoc/extract.rs4
-rw-r--r--src/rustdoc/reexport_pass.rs2
-rw-r--r--src/rustdoc/tystr_pass.rs6
-rw-r--r--src/test/compile-fail/iface-cast.rs8
-rw-r--r--src/test/compile-fail/prim-with-args.rs29
-rw-r--r--src/test/compile-fail/regions-bounds.rs32
-rw-r--r--src/test/compile-fail/regions-iface-1.rs28
-rw-r--r--src/test/compile-fail/regions-iface-2.rs21
-rw-r--r--src/test/compile-fail/regions-iface-3.rs14
-rw-r--r--src/test/run-pass/regions-borrow-evec-at.rs2
-rw-r--r--src/test/run-pass/regions-borrow-evec-fixed.rs1
-rw-r--r--src/test/run-pass/regions-iface.rs23
-rw-r--r--src/test/run-pass/regions-self-impls.rs7
-rw-r--r--src/test/run-pass/regions-self-in-enums.rs4
39 files changed, 849 insertions, 547 deletions
diff --git a/src/librustsyntax/ast.rs b/src/librustsyntax/ast.rs
index 55bb480761f..48e8866d3f5 100644
--- a/src/librustsyntax/ast.rs
+++ b/src/librustsyntax/ast.rs
@@ -37,7 +37,11 @@ type ident = str;
 type fn_ident = option<ident>;
 
 #[auto_serialize]
-type path = {span: span, global: bool, idents: [ident], types: [@ty]};
+type path = {span: span,
+             global: bool,
+             idents: [ident],
+             rp: option<@region>,
+             types: [@ty]};
 
 #[auto_serialize]
 type crate_num = int;
@@ -175,7 +179,7 @@ enum vstore {
     vstore_fixed(option<uint>),   // [1,2,3,4]/_ or 4
     vstore_uniq,                  // [1,2,3,4]/~
     vstore_box,                   // [1,2,3,4]/@
-    vstore_slice(region)          // [1,2,3,4]/&(foo)?
+    vstore_slice(@region)         // [1,2,3,4]/&(foo)?
 }
 
 pure fn is_blockish(p: ast::proto) -> bool {
@@ -462,7 +466,7 @@ enum ty_ {
     ty_uniq(mt),
     ty_vec(mt),
     ty_ptr(mt),
-    ty_rptr(region, mt),
+    ty_rptr(@region, mt),
     ty_rec([ty_field]),
     ty_fn(proto, fn_decl),
     ty_tup([@ty]),
@@ -671,8 +675,8 @@ enum item_ {
                class_ctor,
                region_param
                ),
-    item_iface([ty_param], [ty_method]),
-    item_impl([ty_param], option<@iface_ref> /* iface */,
+    item_iface([ty_param], region_param, [ty_method]),
+    item_impl([ty_param], region_param, option<@iface_ref> /* iface */,
               @ty /* self */, [@method]),
 }
 
diff --git a/src/librustsyntax/ast_util.rs b/src/librustsyntax/ast_util.rs
index f3c7e08ef9f..49a20393a5d 100644
--- a/src/librustsyntax/ast_util.rs
+++ b/src/librustsyntax/ast_util.rs
@@ -248,7 +248,8 @@ fn default_block(stmts1: [@stmt], expr1: option<@expr>, id1: node_id) ->
 }
 
 fn ident_to_path(s: span, i: ident) -> @path {
-    @{span: s, global: false, idents: [i], types: []}
+    @{span: s, global: false, idents: [i],
+      rp: none, types: []}
 }
 
 pure fn is_unguarded(&&a: arm) -> bool {
diff --git a/src/librustsyntax/ext/auto_serialize.rs b/src/librustsyntax/ext/auto_serialize.rs
index 0532a2c987b..7b90709b118 100644
--- a/src/librustsyntax/ext/auto_serialize.rs
+++ b/src/librustsyntax/ext/auto_serialize.rs
@@ -130,11 +130,11 @@ impl helpers for ext_ctxt {
     }
 
     fn path(span: span, strs: [str]) -> @ast::path {
-        @{span: span, global: false, idents: strs, types: []}
+        @{span: span, global: false, idents: strs, rp: none, types: []}
     }
 
     fn path_tps(span: span, strs: [str], tps: [@ast::ty]) -> @ast::path {
-        @{span: span, global: false, idents: strs, types: tps}
+        @{span: span, global: false, idents: strs, rp: none, types: tps}
     }
 
     fn ty_path(span: span, strs: [str], tps: [@ast::ty]) -> @ast::ty {
@@ -193,7 +193,8 @@ impl helpers for ext_ctxt {
     }
 
     fn binder_pat(span: span, nm: str) -> @ast::pat {
-        let path = @{span: span, global: false, idents: [nm], types: []};
+        let path = @{span: span, global: false, idents: [nm],
+                     rp: none, types: []};
         @{id: self.next_id(),
           node: ast::pat_ident(path, none),
           span: span}
diff --git a/src/librustsyntax/ext/build.rs b/src/librustsyntax/ext/build.rs
index ebf57745d9f..516deb1e793 100644
--- a/src/librustsyntax/ext/build.rs
+++ b/src/librustsyntax/ext/build.rs
@@ -30,7 +30,8 @@ fn mk_unary(cx: ext_ctxt, sp: span, op: ast::unop, e: @ast::expr)
 }
 fn mk_path(cx: ext_ctxt, sp: span, idents: [ast::ident]) ->
     @ast::expr {
-    let path = @{span: sp, global: false, idents: idents, types: []};
+    let path = @{span: sp, global: false, idents: idents,
+                 rp: none, types: []};
     let pathexpr = ast::expr_path(path);
     ret @{id: cx.next_id(), node: pathexpr, span: sp};
 }
diff --git a/src/librustsyntax/ext/concat_idents.rs b/src/librustsyntax/ext/concat_idents.rs
index 8d2c89c0d43..409a38b378d 100644
--- a/src/librustsyntax/ext/concat_idents.rs
+++ b/src/librustsyntax/ext/concat_idents.rs
@@ -17,6 +17,6 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
 
     ret @{id: cx.next_id(),
           node: ast::expr_path(@{span: sp, global: false, idents: [res],
-                                 types: []}),
+                                 rp: none, types: []}),
           span: sp};
 }
diff --git a/src/librustsyntax/ext/simplext.rs b/src/librustsyntax/ext/simplext.rs
index f3d6b542d10..81eaa193f95 100644
--- a/src/librustsyntax/ext/simplext.rs
+++ b/src/librustsyntax/ext/simplext.rs
@@ -334,7 +334,8 @@ fn transcribe_path(cx: ext_ctxt, b: bindings, idx_path: @mut [uint],
     if vec::len(p.types) > 0u || vec::len(p.idents) != 1u { ret p; }
     alt follow_for_trans(cx, b.find(p.idents[0]), idx_path) {
       some(match_ident(id)) {
-        {span: id.span, global: false, idents: [id.node], types: []}
+        {span: id.span, global: false, idents: [id.node],
+         rp: none, types: []}
       }
       some(match_path(a_pth)) { *a_pth }
       some(m) { match_error(cx, m, "a path") }
@@ -359,6 +360,7 @@ fn transcribe_expr(cx: ext_ctxt, b: bindings, idx_path: @mut [uint],
                 (expr_path(@{span: id.span,
                              global: false,
                              idents: [id.node],
+                             rp: none,
                              types: []}), id.span)
               }
               some(match_path(a_pth)) { (expr_path(a_pth), s) }
diff --git a/src/librustsyntax/fold.rs b/src/librustsyntax/fold.rs
index e5c2c59a4d2..30e8c5173b2 100644
--- a/src/librustsyntax/fold.rs
+++ b/src/librustsyntax/fold.rs
@@ -287,12 +287,18 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
                    with ctor},
                   rp)
           }
-          item_impl(tps, ifce, ty, methods) {
-              item_impl(tps, option::map(ifce, {|p| fold_iface_ref(p, fld)}),
+          item_impl(tps, rp, ifce, ty, methods) {
+              item_impl(fold_ty_params(tps, fld),
+                        rp,
+                        ifce.map { |p| fold_iface_ref(p, fld) },
                         fld.fold_ty(ty),
-                      vec::map(methods, fld.fold_method))
+                        vec::map(methods, fld.fold_method))
+          }
+          item_iface(tps, rp, methods) {
+            item_iface(fold_ty_params(tps, fld),
+                       rp,
+                       methods)
           }
-          item_iface(tps, methods) { item_iface(tps, methods) }
           item_res(decl, typms, body, did, cid, rp) {
             item_res(fold_fn_decl(decl, fld),
                      fold_ty_params(typms, fld),
@@ -565,6 +571,7 @@ fn noop_fold_ident(&&i: ident, _fld: ast_fold) -> ident { ret i; }
 fn noop_fold_path(&&p: path, fld: ast_fold) -> path {
     ret {span: fld.new_span(p.span), global: p.global,
          idents: vec::map(p.idents, fld.fold_ident),
+         rp: p.rp,
          types: vec::map(p.types, fld.fold_ty)};
 }
 
diff --git a/src/librustsyntax/parse/parser.rs b/src/librustsyntax/parse/parser.rs
index dec7937a416..53d42038afa 100644
--- a/src/librustsyntax/parse/parser.rs
+++ b/src/librustsyntax/parse/parser.rs
@@ -175,7 +175,7 @@ fn parse_type_constr_arg(p: parser) -> @ast::ty_constr_arg {
     if p.token == token::DOT {
         // "*..." notation for record fields
         p.bump();
-        let pth = parse_path(p);
+        let pth = parse_path_without_tps(p);
         carg = ast::carg_ident(pth);
     }
     // No literals yet, I guess?
@@ -196,7 +196,7 @@ fn parse_constr_arg(args: [ast::arg], p: parser) -> @ast::constr_arg {
 
 fn parse_ty_constr(fn_args: [ast::arg], p: parser) -> @ast::constr {
     let lo = p.span.lo;
-    let path = parse_path(p);
+    let path = parse_path_without_tps(p);
     let args: {node: [@ast::constr_arg], span: span} =
         parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
                   {|p| parse_constr_arg(fn_args, p)}, p);
@@ -206,7 +206,7 @@ fn parse_ty_constr(fn_args: [ast::arg], p: parser) -> @ast::constr {
 
 fn parse_constr_in_type(p: parser) -> @ast::ty_constr {
     let lo = p.span.lo;
-    let path = parse_path(p);
+    let path = parse_path_without_tps(p);
     let args: [@ast::ty_constr_arg] =
         parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
                   parse_type_constr_arg, p).node;
@@ -231,52 +231,6 @@ fn parse_type_constraints(p: parser) -> [@ast::ty_constr] {
     ret parse_constrs(parse_constr_in_type, p);
 }
 
-fn parse_ty_postfix(orig_t: ast::ty_, p: parser, colons_before_params: bool,
-                    lo: uint) -> @ast::ty {
-
-
-    fn mk_ty(p: parser, t: ast::ty_, lo: uint, hi: uint) -> @ast::ty {
-        @{id: p.get_id(),
-          node: t,
-          span: mk_sp(lo, hi)}
-    }
-
-    if p.token == token::BINOP(token::SLASH) {
-        let orig_hi = p.last_span.hi;
-        alt maybe_parse_vstore(p) {
-          none { }
-          some(v) {
-            let t = ast::ty_vstore(mk_ty(p, orig_t, lo, orig_hi), v);
-            ret mk_ty(p, t, lo, p.last_span.hi);
-          }
-        }
-    }
-
-    if colons_before_params && p.token == token::MOD_SEP {
-        p.bump();
-        expect(p, token::LT);
-    } else if !colons_before_params && p.token == token::LT {
-        p.bump();
-    } else {
-        ret mk_ty(p, orig_t, lo, p.last_span.hi);
-    }
-
-    // If we're here, we have explicit type parameter instantiation.
-    let seq = parse_seq_to_gt(some(token::COMMA), {|p| parse_ty(p, false)},
-                              p);
-
-    alt orig_t {
-      ast::ty_path(pth, ann) {
-        ret mk_ty(p, ast::ty_path(@{span: mk_sp(lo, p.last_span.hi),
-                                    global: pth.global,
-                                    idents: pth.idents,
-                                    types: seq}, ann),
-                  lo, p.last_span.hi);
-      }
-      _ { p.fatal("type parameter instantiation only allowed for paths"); }
-    }
-}
-
 fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) {
     ret if eat(p, token::RARROW) {
         let lo = p.span.lo;
@@ -295,7 +249,7 @@ fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) {
     }
 }
 
-fn region_from_name(p: parser, s: option<str>) -> ast::region {
+fn region_from_name(p: parser, s: option<str>) -> @ast::region {
     let r = alt s {
       some (string) {
         // FIXME: To be consistent with our type resolution, the
@@ -310,10 +264,26 @@ fn region_from_name(p: parser, s: option<str>) -> ast::region {
       none { ast::re_anon }
     };
 
-    {id: p.get_id(), node: r}
+    @{id: p.get_id(), node: r}
+}
+
+// Parses something like "&x"
+fn parse_region(p: parser) -> @ast::region {
+    expect(p, token::BINOP(token::AND));
+    alt p.token {
+      token::IDENT(sid, _) {
+        p.bump();
+        let n = p.get_str(sid);
+        region_from_name(p, some(n))
+      }
+      _ {
+        region_from_name(p, none)
+      }
+    }
 }
 
-fn parse_region(p: parser) -> ast::region {
+// Parses something like "&x." (note the trailing dot)
+fn parse_region_dot(p: parser) -> @ast::region {
     let name =
         alt p.token {
           token::IDENT(sid, _) if p.look_ahead(1u) == token::DOT {
@@ -384,7 +354,7 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty {
         t
     } else if p.token == token::BINOP(token::AND) {
         p.bump();
-        let region = parse_region(p);
+        let region = parse_region_dot(p);
         let mt = parse_mt(p);
         ast::ty_rptr(region, mt)
     } else if eat_keyword(p, "fn") {
@@ -398,10 +368,28 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty {
         expect_keyword(p, "fn");
         ast::ty_fn(ast::proto_bare, parse_ty_fn(p))
     } else if p.token == token::MOD_SEP || is_ident(p.token) {
-        let path = parse_path(p);
+        let path = parse_path_with_tps(p, colons_before_params);
         ast::ty_path(path, p.get_id())
     } else { p.fatal("expecting type"); };
-    ret parse_ty_postfix(t, p, colons_before_params, lo);
+
+    fn mk_ty(p: parser, t: ast::ty_, lo: uint, hi: uint) -> @ast::ty {
+        @{id: p.get_id(),
+          node: t,
+          span: mk_sp(lo, hi)}
+    }
+
+    let ty = mk_ty(p, t, lo, p.last_span.hi);
+
+    // Consider a vstore suffix like /@ or /~
+    alt maybe_parse_vstore(p) {
+      none {
+        ret ty;
+      }
+      some(v) {
+        let t1 = ast::ty_vstore(ty, v);
+        ret mk_ty(p, t1, lo, p.last_span.hi);
+      }
+    }
 }
 
 fn parse_arg_mode(p: parser) -> ast::mode {
@@ -484,17 +472,7 @@ fn maybe_parse_vstore(p: parser) -> option<ast::vstore> {
             p.bump(); some(ast::vstore_fixed(some(i as uint)))
           }
           token::BINOP(token::AND) {
-            p.bump();
-            alt p.token {
-              token::IDENT(sid, _) {
-                p.bump();
-                let n = p.get_str(sid);
-                some(ast::vstore_slice(region_from_name(p, some(n))))
-              }
-              _ {
-                some(ast::vstore_slice(region_from_name(p, none)))
-              }
-            }
+            some(ast::vstore_slice(parse_region(p)))
           }
           _ {
             none
@@ -530,18 +508,19 @@ fn parse_lit(p: parser) -> ast::lit {
     ret {node: lit, span: mk_sp(lo, p.last_span.hi)};
 }
 
-fn parse_path(p: parser) -> @ast::path {
+fn parse_path_without_tps(p: parser) -> @ast::path {
     let lo = p.span.lo;
     let global = eat(p, token::MOD_SEP);
     let mut ids = [parse_ident(p)];
     while p.look_ahead(1u) != token::LT && eat(p, token::MOD_SEP) {
         ids += [parse_ident(p)];
     }
-    @{span: mk_sp(lo, p.last_span.hi), global: global, idents: ids, types: []}
+    @{span: mk_sp(lo, p.last_span.hi), global: global,
+      idents: ids, rp: none, types: []}
 }
 
 fn parse_value_path(p: parser) -> @ast::path {
-    let pt = parse_path(p);
+    let pt = parse_path_without_tps(p);
     let last_word = vec::last(pt.idents);
     if is_restricted_keyword(p, last_word) {
         p.fatal("found " + last_word + " in expression position");
@@ -549,16 +528,45 @@ fn parse_value_path(p: parser) -> @ast::path {
     pt
 }
 
-fn parse_path_and_ty_param_substs(p: parser, colons: bool) -> @ast::path {
+fn parse_path_with_tps(p: parser, colons: bool) -> @ast::path {
+    #debug["parse_path_with_tps(colons=%b)", colons];
+
     let lo = p.span.lo;
-    let path = parse_path(p);
-    let b = if colons { eat(p, token::MOD_SEP) }
-            else { p.token == token::LT };
-    if b {
-        let seq = parse_seq_lt_gt(some(token::COMMA),
-                                  {|p| parse_ty(p, false)}, p);
-        @{span: mk_sp(lo, seq.span.hi), types: seq.node with *path}
-    } else { path }
+    let path = parse_path_without_tps(p);
+    if colons && !eat(p, token::MOD_SEP) {
+        ret path;
+    }
+
+    // Parse the region parameter, if any, which will
+    // be written "foo/&x"
+    let rp = {
+        // Hack: avoid parsing vstores like /@ and /~.  This is painful
+        // because the notation for region bounds and the notation for vstores
+        // is... um... the same.  I guess that's my fault.  This is still not
+        // ideal as for str/& we end up parsing more than we ought to and have
+        // to sort it out later.
+        if p.token == token::BINOP(token::SLASH)
+            && p.look_ahead(1u) == token::BINOP(token::AND) {
+
+            expect(p, token::BINOP(token::SLASH));
+            some(parse_region(p))
+        } else {
+            none
+        }
+    };
+
+    // Parse any type parameters which may appear:
+    let tps = {
+        if p.token == token::LT {
+            parse_seq_lt_gt(some(token::COMMA), {|p| parse_ty(p, false)}, p)
+        } else {
+            {node: [], span: path.span}
+        }
+    };
+
+    ret @{span: mk_sp(lo, tps.span.hi),
+          rp: rp,
+          types: tps.node with *path};
 }
 
 fn parse_mutability(p: parser) -> ast::mutability {
@@ -803,7 +811,7 @@ fn parse_bottom_expr(p: parser) -> pexpr {
                   is_ident(p.token) && !is_keyword(p, "true") &&
                       !is_keyword(p, "false") {
         check_restricted_keywords(p);
-        let pth = parse_path_and_ty_param_substs(p, true);
+        let pth = parse_path_with_tps(p, true);
         hi = pth.span.hi;
         ex = ast::expr_path(pth);
     } else {
@@ -850,7 +858,7 @@ fn parse_syntax_ext_naked(p: parser, lo: uint) -> @ast::expr {
       token::IDENT(_, _) {}
       _ { p.fatal("expected a syntax expander name"); }
     }
-    let pth = parse_path(p);
+    let pth = parse_path_without_tps(p);
     //temporary for a backwards-compatible cycle:
     let sep = seq_sep(token::COMMA);
     let mut e = none;
@@ -1424,7 +1432,7 @@ fn parse_pat(p: parser) -> @ast::pat {
                       else { none };
             pat = ast::pat_ident(name, sub);
         } else {
-            let enum_path = parse_path_and_ty_param_substs(p, true);
+            let enum_path = parse_path_with_tps(p, true);
             hi = enum_path.span.hi;
             let mut args: [@ast::pat] = [];
             let mut star_pat = false;
@@ -1779,24 +1787,39 @@ fn parse_method(p: parser, pr: ast::privacy) -> @ast::method {
 }
 
 fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item {
-    let lo = p.last_span.lo, ident = parse_ident(p),
-        tps = parse_ty_params(p), meths = parse_ty_methods(p);
+    let lo = p.last_span.lo, ident = parse_ident(p);
+    let rp = parse_region_param(p);
+    let tps = parse_ty_params(p);
+    let meths = parse_ty_methods(p);
     ret mk_item(p, lo, p.last_span.hi, ident,
-                ast::item_iface(tps, meths), attrs);
+                ast::item_iface(tps, rp, meths), attrs);
 }
 
-// Parses three variants (with the initial params always optional):
-//    impl <T: copy> of to_str for [T] { ... }
-//    impl name<T> of to_str for [T] { ... }
-//    impl name<T> for [T] { ... }
+// Parses three variants (with the region/type params always optional):
+//    impl /&<T: copy> of to_str for [T] { ... }
+//    impl name/&<T> of to_str for [T] { ... }
+//    impl name/&<T> for [T] { ... }
 fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item {
     let lo = p.last_span.lo;
-    let mut (ident, tps) = if !is_keyword(p, "of") {
-        if p.token == token::LT { (none, parse_ty_params(p)) }
-        else { (some(parse_ident(p)), parse_ty_params(p)) }
-    } else { (none, []) };
+    fn wrap_path(p: parser, pt: @ast::path) -> @ast::ty {
+        @{id: p.get_id(), node: ast::ty_path(pt, p.get_id()), span: pt.span}
+    }
+    let mut (ident, rp, tps) = {
+        if p.token == token::LT {
+            (none, ast::rp_none, parse_ty_params(p))
+        } else if p.token == token::BINOP(token::SLASH) {
+            (none, parse_region_param(p), parse_ty_params(p))
+        }
+        else if is_keyword(p, "of") {
+            (none, ast::rp_none, [])
+        } else {
+            let id = parse_ident(p);
+            let rp = parse_region_param(p);
+            (some(id), rp, parse_ty_params(p))
+        }
+    };
     let ifce = if eat_keyword(p, "of") {
-        let path = parse_path_and_ty_param_substs(p, false);
+        let path = parse_path_with_tps(p, false);
         if option::is_none(ident) {
             ident = some(vec::last(path.idents));
         }
@@ -1812,7 +1835,7 @@ fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item {
     expect(p, token::LBRACE);
     while !eat(p, token::RBRACE) { meths += [parse_method(p, ast::pub)]; }
     ret mk_item(p, lo, p.last_span.hi, ident,
-                ast::item_impl(tps, ifce, ty, meths), attrs);
+                ast::item_impl(tps, rp, ifce, ty, meths), attrs);
 }
 
 fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
@@ -1842,21 +1865,32 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
                 attrs);
 }
 
-// Instantiates ident <i> with references to <typarams> as arguments
+// Instantiates ident <i> with references to <typarams> as arguments.  Used to
+// create a path that refers to a class which will be defined as the return
+// type of the ctor function.
 fn ident_to_path_tys(p: parser, i: ast::ident,
+                     rp: ast::region_param,
                      typarams: [ast::ty_param]) -> @ast::path {
     let s = p.last_span;
+
+    // Hack.  But then, this whole function is in service of a hack.
+    let a_r = alt rp {
+      ast::rp_none { none }
+      ast::rp_self { some(region_from_name(p, some("self"))) }
+    };
+
     @{span: s, global: false, idents: [i],
+      rp: a_r,
       types: vec::map(typarams, {|tp|
           @{id: p.get_id(),
-            node: ast::ty_path(ident_to_path(s, tp.ident),
-                               p.get_id()),
+            node: ast::ty_path(ident_to_path(s, tp.ident), p.get_id()),
             span: s}})
      }
 }
 
 fn parse_iface_ref(p:parser) -> @ast::iface_ref {
-    @{path: parse_path(p), id: p.get_id()}
+    @{path: parse_path_with_tps(p, false),
+      id: p.get_id()}
 }
 
 fn parse_iface_ref_list(p:parser) -> [@ast::iface_ref] {
@@ -1869,7 +1903,7 @@ fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item {
     let class_name = parse_value_ident(p);
     let rp = parse_region_param(p);
     let ty_params = parse_ty_params(p);
-    let class_path = ident_to_path_tys(p, class_name, ty_params);
+    let class_path = ident_to_path_tys(p, class_name, rp, ty_params);
     let ifaces : [@ast::iface_ref] = if eat_keyword(p, "implements")
                                        { parse_iface_ref_list(p) }
                                     else { [] };
@@ -2240,7 +2274,7 @@ fn parse_view_path(p: parser) -> @ast::view_path {
             path += [id];
         }
         let path = @{span: mk_sp(lo, p.span.hi), global: false,
-                     idents: path, types: []};
+                     idents: path, rp: none, types: []};
         ret @spanned(lo, p.span.hi,
                      ast::view_path_simple(first_ident, path, p.get_id()));
       }
@@ -2264,7 +2298,8 @@ fn parse_view_path(p: parser) -> @ast::view_path {
                               seq_sep(token::COMMA),
                               parse_path_list_ident, p).node;
                 let path = @{span: mk_sp(lo, p.span.hi),
-                             global: false, idents: path, types: []};
+                             global: false, idents: path,
+                             rp: none, types: []};
                 ret @spanned(lo, p.span.hi,
                              ast::view_path_list(path, idents, p.get_id()));
               }
@@ -2273,7 +2308,8 @@ fn parse_view_path(p: parser) -> @ast::view_path {
               token::BINOP(token::STAR) {
                 p.bump();
                 let path = @{span: mk_sp(lo, p.span.hi),
-                             global: false, idents: path, types: []};
+                             global: false, idents: path,
+                             rp: none, types: []};
                 ret @spanned(lo, p.span.hi,
                              ast::view_path_glob(path, p.get_id()));
               }
@@ -2286,7 +2322,7 @@ fn parse_view_path(p: parser) -> @ast::view_path {
     }
     let last = path[vec::len(path) - 1u];
     let path = @{span: mk_sp(lo, p.span.hi), global: false,
-                 idents: path, types: []};
+                 idents: path, rp: none, types: []};
     ret @spanned(lo, p.span.hi,
                  ast::view_path_simple(last, path, p.get_id()));
 }
diff --git a/src/librustsyntax/print/pprust.rs b/src/librustsyntax/print/pprust.rs
index e7be554fca8..0ccf2399292 100644
--- a/src/librustsyntax/print/pprust.rs
+++ b/src/librustsyntax/print/pprust.rs
@@ -325,11 +325,14 @@ fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) {
     for nmod.items.each {|item| print_native_item(s, item); }
 }
 
-fn print_region(s: ps, region: ast::region) {
+fn print_region(s: ps, region: @ast::region) {
     alt region.node {
-      ast::re_anon { /* no-op */ }
-      ast::re_named(name) { word(s.s, name); word(s.s, "."); }
-      ast::re_static { word(s.s, "static"); word(s.s, "."); }
+      ast::re_anon { word_space(s, "&"); }
+      ast::re_static { word_space(s, "&static"); }
+      ast::re_named(name) {
+        word(s.s, "&");
+        word_space(s, name);
+      }
     }
 }
 
@@ -353,8 +356,10 @@ fn print_type(s: ps, &&ty: @ast::ty) {
       }
       ast::ty_ptr(mt) { word(s.s, "*"); print_mt(s, mt); }
       ast::ty_rptr(region, mt) {
-        word(s.s, "&");
-        print_region(s, region);
+        alt region.node {
+          ast::re_anon { word(s.s, "&"); }
+          _ { print_region(s, region); word(s.s, "."); }
+        }
         print_mt(s, mt);
       }
       ast::ty_rec(fields) {
@@ -556,9 +561,10 @@ fn print_item(s: ps, &&item: @ast::item) {
           }
           bclose(s, item.span);
        }
-      ast::item_impl(tps, ifce, ty, methods) {
+      ast::item_impl(tps, rp, ifce, ty, methods) {
         head(s, "impl");
         word(s.s, item.ident);
+        print_region_param(s, rp);
         print_type_params(s, tps);
         space(s.s);
         option::iter(ifce, {|p|
@@ -575,9 +581,10 @@ fn print_item(s: ps, &&item: @ast::item) {
         }
         bclose(s, item.span);
       }
-      ast::item_iface(tps, methods) {
+      ast::item_iface(tps, rp, methods) {
         head(s, "iface");
         word(s.s, item.ident);
+        print_region_param(s, rp);
         print_type_params(s, tps);
         word(s.s, " ");
         bopen(s);
@@ -831,16 +838,7 @@ fn print_vstore(s: ps, t: ast::vstore) {
       ast::vstore_fixed(none) { word_space(s, "/_"); }
       ast::vstore_uniq { word_space(s, "/~"); }
       ast::vstore_box { word_space(s, "/@"); }
-      ast::vstore_slice(r) {
-        alt r.node {
-          ast::re_anon { word_space(s, "/&"); }
-          ast::re_static { word_space(s, "/&static"); }
-          ast::re_named(name) {
-            word(s.s, "/&");
-            word_space(s, name);
-          }
-        }
-      }
+      ast::vstore_slice(r) { word(s.s, "/"); print_region(s, r); }
     }
 }
 
@@ -1225,11 +1223,22 @@ fn print_path(s: ps, &&path: @ast::path, colons_before_params: bool) {
         if first { first = false; } else { word(s.s, "::"); }
         word(s.s, id);
     }
-    if vec::len(path.types) > 0u {
+    if path.rp.is_some() || !path.types.is_empty() {
         if colons_before_params { word(s.s, "::"); }
-        word(s.s, "<");
-        commasep(s, inconsistent, path.types, print_type);
-        word(s.s, ">");
+
+        alt path.rp {
+          none { /* ok */ }
+          some(r) {
+            word(s.s, "/");
+            print_region(s, r);
+          }
+        }
+
+        if !path.types.is_empty() {
+            word(s.s, "<");
+            commasep(s, inconsistent, path.types, print_type);
+            word(s.s, ">");
+        }
     }
 }
 
diff --git a/src/librustsyntax/visit.rs b/src/librustsyntax/visit.rs
index ad6b787f180..04b6c002cb2 100644
--- a/src/librustsyntax/visit.rs
+++ b/src/librustsyntax/visit.rs
@@ -132,7 +132,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
             for vr.node.args.each {|va| v.visit_ty(va.ty, e, v); }
         }
       }
-      item_impl(tps, ifce, ty, methods) {
+      item_impl(tps, _rp, ifce, ty, methods) {
         v.visit_ty_params(tps, e, v);
         option::iter(ifce, {|p| visit_path(p.path, e, v)});
         v.visit_ty(ty, e, v);
@@ -149,7 +149,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
           visit_class_ctor_helper(ctor, i.ident, tps,
                                   ast_util::local_def(i.id), e, v);
       }
-      item_iface(tps, methods) {
+      item_iface(tps, _rp, methods) {
         v.visit_ty_params(tps, e, v);
         for methods.each {|m|
             for m.decl.inputs.each {|a| v.visit_ty(a.ty, e, v); }
diff --git a/src/rustc/front/test.rs b/src/rustc/front/test.rs
index 270b2a8b7e3..258c49daa9d 100644
--- a/src/rustc/front/test.rs
+++ b/src/rustc/front/test.rs
@@ -207,7 +207,7 @@ fn nospan<T: copy>(t: T) -> ast::spanned<T> {
 }
 
 fn path_node(ids: [ast::ident]) -> @ast::path {
-    @{span: dummy_sp(), global: false, idents: ids, types: []}
+    @{span: dummy_sp(), global: false, idents: ids, rp: none, types: []}
 }
 
 fn mk_tests(cx: test_ctxt) -> @ast::item {
diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs
index ae3bc4e0a2c..a1c996dccf1 100644
--- a/src/rustc/metadata/encoder.rs
+++ b/src/rustc/metadata/encoder.rs
@@ -185,14 +185,14 @@ fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt,
             ebml_w.end_tag();
             encode_enum_variant_paths(ebml_w, variants, path, index);
           }
-          item_iface(_, _) {
+          item_iface(*) {
             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();
           }
-          item_impl(_, _, _, _) {}
+          item_impl(*) {}
         }
     }
 }
@@ -649,11 +649,12 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
         encode_path(ebml_w, path, ast_map::path_name(item.ident));
         ebml_w.end_tag();
       }
-      item_impl(tps, ifce, _, methods) {
+      item_impl(tps, rp, ifce, _, methods) {
         add_to_index();
         ebml_w.start_tag(tag_items_data_item);
         encode_def_id(ebml_w, local_def(item.id));
         encode_family(ebml_w, 'i');
+        encode_region_param(ebml_w, rp);
         encode_type_param_bounds(ebml_w, ecx, tps);
         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
         encode_name(ebml_w, item.ident);
@@ -681,11 +682,12 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
                    should_inline(m.attrs), item.id, m, tps + m.tps);
         }
       }
-      item_iface(tps, ms) {
+      item_iface(tps, rp, ms) {
         add_to_index();
         ebml_w.start_tag(tag_items_data_item);
         encode_def_id(ebml_w, local_def(item.id));
         encode_family(ebml_w, 'I');
+        encode_region_param(ebml_w, rp);
         encode_type_param_bounds(ebml_w, ecx, tps);
         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
         encode_name(ebml_w, item.ident);
diff --git a/src/rustc/metadata/tydecode.rs b/src/rustc/metadata/tydecode.rs
index 872dfa8b8d4..46c39256938 100644
--- a/src/rustc/metadata/tydecode.rs
+++ b/src/rustc/metadata/tydecode.rs
@@ -104,7 +104,8 @@ fn parse_path(st: @pstate) -> @ast::path {
           c {
             if c == '(' {
                 ret @{span: ast_util::dummy_sp(),
-                      global: false, idents: idents, types: []};
+                      global: false, idents: idents,
+                      rp: none, types: []};
             } else { idents += [parse_ident_(st, is_last)]; }
           }
         }
@@ -286,12 +287,11 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
         ret ty::mk_enum(st.tcx, def, substs);
       }
       'x' {
-        assert (next(st) == '[');
+        assert next(st) == '[';
         let def = parse_def(st, conv);
-        let mut params: [ty::t] = [];
-        while peek(st) != ']' { params += [parse_ty(st, conv)]; }
-        st.pos = st.pos + 1u;
-        ret ty::mk_iface(st.tcx, def, params);
+        let substs = parse_substs(st, conv);
+        assert next(st) == ']';
+        ret ty::mk_iface(st.tcx, def, substs);
       }
       'p' {
         let did = parse_def(st, conv);
@@ -299,10 +299,9 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
       }
       's' {
         assert next(st) == '[';
-        let mut params = [];
-        while peek(st) != ']' { params += [parse_ty(st, conv)]; }
-        st.pos += 1u;
-        ret ty::mk_self(st.tcx, params);
+        let substs = parse_substs(st, conv);
+        assert next(st) == ']';
+        ret ty::mk_self(st.tcx, substs);
       }
       '@' { ret ty::mk_box(st.tcx, parse_mt(st, conv)); }
       '~' { ret ty::mk_uniq(st.tcx, parse_mt(st, conv)); }
@@ -344,7 +343,7 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
         parse_ty_rust_fn(st, conv, proto)
       }
       'r' {
-        assert (next(st) == '[');
+        assert next(st) == '[';
         let def = parse_def(st, conv);
         let inner = parse_ty(st, conv);
         let substs = parse_substs(st, conv);
diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs
index 763e710b07a..130e7f40916 100644
--- a/src/rustc/metadata/tyencode.rs
+++ b/src/rustc/metadata/tyencode.rs
@@ -220,11 +220,11 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
         enc_substs(w, cx, substs);
         w.write_char(']');
       }
-      ty::ty_iface(def, tys) {
+      ty::ty_iface(def, substs) {
         w.write_str("x["/&);
         w.write_str(cx.ds(def));
         w.write_char('|');
-        for tys.each {|t| enc_ty(w, cx, t); }
+        enc_substs(w, cx, substs);
         w.write_char(']');
       }
       ty::ty_tup(ts) {
@@ -281,9 +281,9 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
         w.write_char('|');
         w.write_str(uint::str(id));
       }
-      ty::ty_self(tps) {
+      ty::ty_self(substs) {
         w.write_str("s["/&);
-        for tps.each {|t| enc_ty(w, cx, t); }
+        enc_substs(w, cx, substs);
         w.write_char(']');
       }
       ty::ty_type { w.write_char('Y'); }
diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs
index 2988cdc6f40..f2300f9695a 100644
--- a/src/rustc/middle/ast_map.rs
+++ b/src/rustc/middle/ast_map.rs
@@ -177,7 +177,7 @@ fn map_item(i: @item, cx: ctx, v: vt) {
     let item_path = @cx.path;
     cx.map.insert(i.id, node_item(i, item_path));
     alt i.node {
-      item_impl(_, _, _, ms) {
+      item_impl(_, _, _, _, ms) {
         let impl_did = ast_util::local_def(i.id);
         for ms.each {|m|
             map_method(impl_did, extend(cx, i.ident), m, cx);
diff --git a/src/rustc/middle/infer.rs b/src/rustc/middle/infer.rs
index 1e513d3da8c..d5e22815b7b 100644
--- a/src/rustc/middle/infer.rs
+++ b/src/rustc/middle/infer.rs
@@ -15,6 +15,7 @@ import util::common::{indent, indenter};
 export infer_ctxt;
 export new_infer_ctxt;
 export mk_subty;
+export mk_subr;
 export mk_eqty;
 export mk_assignty;
 export resolve_shallow;
@@ -73,6 +74,11 @@ fn mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
     indent {|| cx.commit {|| sub(cx).tys(a, b) } }.to_ures()
 }
 
+fn mk_subr(cx: infer_ctxt, a: ty::region, b: ty::region) -> ures {
+    #debug["mk_subr(%s <: %s)", a.to_str(cx), b.to_str(cx)];
+    indent {|| cx.commit {|| sub(cx).regions(a, b) } }.to_ures()
+}
+
 fn mk_eqty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
     #debug["mk_eqty(%s <: %s)", a.to_str(cx), b.to_str(cx)];
     indent {|| cx.commit {|| cx.eq_tys(a, b) } }.to_ures()
@@ -1120,10 +1126,10 @@ fn super_tys<C:combine>(
         }
       }
 
-      (ty::ty_iface(a_id, a_tps), ty::ty_iface(b_id, b_tps))
+      (ty::ty_iface(a_id, a_substs), ty::ty_iface(b_id, b_substs))
       if a_id == b_id {
-        self.tps(a_tps, b_tps).chain {|tps|
-            ok(ty::mk_iface(tcx, a_id, tps))
+        self.substs(a_substs, b_substs).chain {|substs|
+            ok(ty::mk_iface(tcx, a_id, substs))
         }
       }
 
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index 1d6d506dbc1..150466a7097 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -435,14 +435,14 @@ fn resolve_names(e: @env, c: @ast::crate) {
           non-class items
          */
         alt i.node {
-           ast::item_class(_, ifaces, _, _, _) {
-             /* visit the iface paths... */
-              for ifaces.each {|p| resolve_iface_ref(p, sc, e)};
-           }
-           ast::item_impl(_, ifce, _, _) {
-               option::iter(ifce, {|p| resolve_iface_ref(p, sc, e)});
-           }
-           _ {}
+          ast::item_class(_, ifaces, _, _, _) {
+            /* visit the iface paths... */
+            for ifaces.each {|p| resolve_iface_ref(p, sc, e) ;}
+          }
+          ast::item_impl(_, _, ifce, _, _) {
+            ifce.iter { |p| resolve_iface_ref(p, sc, e); }
+          }
+          _ {}
         }
     }
 
@@ -540,7 +540,7 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
 
     let sc = cons(scope_item(i), @sc);
     alt i.node {
-      ast::item_impl(tps, ifce, sty, methods) {
+      ast::item_impl(tps, _, ifce, sty, methods) {
         visit::visit_ty_params(tps, sc, v);
         option::iter(ifce) {|p| visit::visit_path(p.path, sc, v)};
         v.visit_ty(sty, sc, v);
@@ -551,7 +551,7 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
                        m.decl, m.body, m.span, m.id, msc, v);
         }
       }
-      ast::item_iface(tps, methods) {
+      ast::item_iface(tps, _, methods) {
         visit::visit_ty_params(tps, sc, v);
         for methods.each {|m|
             let msc = cons(scope_method(i.id, tps + m.tps), @sc);
@@ -1008,13 +1008,13 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace,
           }
           scope_item(it) {
             alt it.node {
-              ast::item_impl(tps, _, _, _) {
+              ast::item_impl(tps, _, _, _, _) {
                 if ns == ns_type { ret lookup_in_ty_params(e, name, 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, _) {
+              ast::item_iface(tps, _, _) {
                 if ns == ns_type {
                     if name == "self" {
                         ret some(def_self(it.id));
@@ -1286,7 +1286,7 @@ fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint,
 
 fn found_def_item(i: @ast::item, ns: namespace) -> option<def> {
     alt i.node {
-      ast::item_const(_, _) {
+      ast::item_const(*) {
         if ns == ns_val {
             ret some(ast::def_const(local_def(i.id))); }
       }
@@ -1301,7 +1301,7 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option<def> {
       ast::item_native_mod(_) {
         if ns == ns_module { ret some(ast::def_native_mod(local_def(i.id))); }
       }
-      ast::item_ty(_, _, _) | item_iface(_, _) | item_enum(_, _, _) {
+      ast::item_ty(*) | item_iface(*) | item_enum(*) {
         if ns == ns_type { ret some(ast::def_ty(local_def(i.id))); }
       }
       ast::item_res(_, _, _, _, ctor_id, _) {
@@ -1313,12 +1313,12 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option<def> {
           _ { }
         }
       }
-      ast::item_class(_, _, _, _, _) {
+      ast::item_class(*) {
           if ns == ns_type {
             ret some(ast::def_class(local_def(i.id)));
           }
       }
-      ast::item_impl(_,_,_,_) { /* ??? */ }
+      ast::item_impl(*) { /* ??? */ }
     }
     ret none;
 }
@@ -1607,8 +1607,7 @@ fn index_mod(md: ast::_mod) -> mod_index {
         alt it.node {
           ast::item_const(_, _) | ast::item_fn(_, _, _) | ast::item_mod(_) |
           ast::item_native_mod(_) | ast::item_ty(_, _, _) |
-          ast::item_res(_, _, _, _, _, _) |
-          ast::item_impl(_, _, _, _) | ast::item_iface(_, _) {
+          ast::item_res(*) | ast::item_impl(*) | ast::item_iface(*) {
             add_to_index(index, it.ident, mie_item(it));
           }
           ast::item_enum(variants, _, _) {
@@ -1753,11 +1752,11 @@ fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) {
         ensure_unique(*e, i.span, ty_params, {|tp| tp.ident},
                       "type parameter");
       }
-      ast::item_iface(_, methods) {
+      ast::item_iface(_, _, methods) {
         ensure_unique(*e, i.span, methods, {|m| m.ident},
                       "method");
       }
-      ast::item_impl(_, _, _, methods) {
+      ast::item_impl(_, _, _, _, methods) {
         ensure_unique(*e, i.span, methods, {|m| m.ident},
                       "method");
       }
@@ -1832,13 +1831,13 @@ fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) {
                   ast::item_mod(_) | ast::item_native_mod(_) {
                     add_name(mods, it.span, it.ident);
                   }
-                  ast::item_const(_, _) | ast::item_fn(_, _, _) {
+                  ast::item_const(_, _) | ast::item_fn(*) {
                     add_name(values, it.span, it.ident);
                   }
-                  ast::item_ty(_, _, _) | ast::item_iface(_, _) {
+                  ast::item_ty(*) | ast::item_iface(*) {
                     add_name(types, it.span, it.ident);
                   }
-                  ast::item_res(_, _, _, _, _, _) {
+                  ast::item_res(*) {
                     add_name(types, it.span, it.ident);
                     add_name(values, it.span, it.ident);
                   }
@@ -2196,7 +2195,7 @@ fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl],
                       name: option<ident>,
                       ck_exports: option<@indexed_mod>) {
     alt i.node {
-      ast::item_impl(_, ifce, _, mthds) {
+      ast::item_impl(_, _, ifce, _, mthds) {
         if alt name { some(n) { n == i.ident } _ { true } } &&
            alt ck_exports {
              some(m) { is_exported(e, i.ident, m) }
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 88df4687d61..6f05a0df434 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -4477,7 +4477,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
             }
         }
       }
-      ast::item_impl(tps, _, _, ms) {
+      ast::item_impl(tps, _rp, _, _, ms) {
         impl::trans_impl(ccx, *path, item.ident, ms, tps);
       }
       ast::item_res(decl, tps, body, dtor_id, ctor_id, _) {
diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs
index 8b1873247d3..b511d653bdf 100644
--- a/src/rustc/middle/trans/impl.rs
+++ b/src/rustc/middle/trans/impl.rs
@@ -90,7 +90,7 @@ fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
                     name: ast::ident) -> ast::def_id {
     if impl_id.crate == ast::local_crate {
         alt check ccx.tcx.items.get(impl_id.node) {
-          ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) {
+          ast_map::node_item(@{node: ast::item_impl(_, _, _, _, ms), _}, _) {
             method_from_methods(ms, name)
           }
           ast_map::node_item(@{node:
diff --git a/src/rustc/middle/trans/reachable.rs b/src/rustc/middle/trans/reachable.rs
index 05cc2224384..bd4800c970a 100644
--- a/src/rustc/middle/trans/reachable.rs
+++ b/src/rustc/middle/trans/reachable.rs
@@ -94,7 +94,7 @@ fn traverse_public_item(cx: ctx, item: @item) {
             traverse_inline_body(cx, blk);
         }
       }
-      item_impl(tps, _, _, ms) {
+      item_impl(tps, _, _, _, ms) {
         for vec::each(ms) {|m|
             if tps.len() > 0u || m.tps.len() > 0u ||
                attr::find_inline_attr(m.attrs) != attr::ia_none {
@@ -117,8 +117,8 @@ fn traverse_public_item(cx: ctx, item: @item) {
             }
         }
       }
-      item_const(_, _) | item_ty(_, _, _) |
-      item_enum(_, _, _) | item_iface(_, _) {}
+      item_const(*) | item_ty(*) |
+      item_enum(*) | item_iface(*) {}
     }
 }
 
diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs
index 03f5a56a1c0..4cc00940202 100644
--- a/src/rustc/middle/tstate/pre_post_conditions.rs
+++ b/src/rustc/middle/tstate/pre_post_conditions.rs
@@ -48,7 +48,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) {
       }
       item_mod(m) { find_pre_post_mod(m); }
       item_native_mod(nm) { find_pre_post_native_mod(nm); }
-      item_ty(_, _, _) | item_enum(_, _, _) | item_iface(_, _) { ret; }
+      item_ty(*) | item_enum(*) | item_iface(*) { ret; }
       item_res(_, _, body, dtor_id, _, _) {
         let fcx =
             {enclosing: ccx.fm.get(dtor_id),
@@ -60,7 +60,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) {
       item_class(_,_,_,_,_) {
           fail "find_pre_post_item: shouldn't be called on item_class";
       }
-      item_impl(_, _, _, ms) {
+      item_impl(_, _, _, _, ms) {
         for ms.each {|m| find_pre_post_method(ccx, m); }
       }
     }
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 2f49958455f..9830fe9c36b 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -325,14 +325,14 @@ enum sty {
     ty_rptr(region, mt),
     ty_rec([field]),
     ty_fn(fn_ty),
-    ty_iface(def_id, [t]),
+    ty_iface(def_id, substs),
     ty_class(def_id, substs),
     ty_res(def_id, t, substs),
     ty_tup([t]),
 
     ty_var(ty_vid), // type variable during typechecking
     ty_param(uint, def_id), // type parameter
-    ty_self([t]), // interface method self type
+    ty_self(substs), // interface method self type
 
     ty_type, // type_desc*
     ty_opaque_box, // used by monomorphizer to represent any @ box
@@ -520,16 +520,10 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
       ty_opaque_box {}
       ty_param(_, _) { has_params = true; }
       ty_var(_) | ty_self(_) { has_vars = true; }
-      ty_enum(_, substs) | ty_class(_, substs) {
+      ty_enum(_, substs) | ty_class(_, substs) | ty_iface(_, substs) {
         derive_sflags(has_params, has_vars, has_regions,
                       has_resources, substs);
       }
-      ty_iface(_, tys) {
-        for tys.each {|tt|
-            derive_flags(has_params, has_vars, has_regions,
-                         has_resources, tt);
-        }
-      }
       ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_evec(m, _) | ty_ptr(m) {
         derive_flags(has_params, has_vars, has_regions,
                      has_resources, m.ty);
@@ -652,8 +646,8 @@ fn mk_tup(cx: ctxt, ts: [t]) -> t { mk_t(cx, ty_tup(ts)) }
 
 fn mk_fn(cx: ctxt, fty: fn_ty) -> t { mk_t(cx, ty_fn(fty)) }
 
-fn mk_iface(cx: ctxt, did: ast::def_id, tys: [t]) -> t {
-    mk_t(cx, ty_iface(did, tys))
+fn mk_iface(cx: ctxt, did: ast::def_id, substs: substs) -> t {
+    mk_t(cx, ty_iface(did, substs))
 }
 
 fn mk_class(cx: ctxt, class_id: ast::def_id, substs: substs) -> t {
@@ -667,7 +661,7 @@ fn mk_res(cx: ctxt, did: ast::def_id,
 
 fn mk_var(cx: ctxt, v: ty_vid) -> t { mk_t(cx, ty_var(v)) }
 
-fn mk_self(cx: ctxt, tps: [t]) -> t { mk_t(cx, ty_self(tps)) }
+fn mk_self(cx: ctxt, substs: substs) -> t { mk_t(cx, ty_self(substs)) }
 
 fn mk_param(cx: ctxt, n: uint, k: def_id) -> t { mk_t(cx, ty_param(n, k)) }
 
@@ -712,12 +706,10 @@ fn maybe_walk_ty(ty: t, f: fn(t) -> bool) {
       ty_ptr(tm) | ty_rptr(_, tm) {
         maybe_walk_ty(tm.ty, f);
       }
-      ty_enum(_, substs) | ty_class(_, substs) {
+      ty_enum(_, substs) | ty_class(_, substs) |
+      ty_iface(_, substs) | ty_self(substs) {
         for substs.tps.each {|subty| maybe_walk_ty(subty, f); }
       }
-      ty_iface(_, subtys) |ty_self(subtys) {
-        for subtys.each {|subty| maybe_walk_ty(subty, f); }
-      }
       ty_rec(fields) {
         for fields.each {|fl| maybe_walk_ty(fl.mt.ty, f); }
       }
@@ -764,11 +756,11 @@ fn fold_sty(sty: sty, fldop: fn(t) -> t) -> sty {
       ty_enum(tid, substs) {
         ty_enum(tid, fold_substs(substs, fldop))
       }
-      ty_iface(did, subtys) {
-        ty_iface(did, vec::map(subtys) {|t| fldop(t) })
+      ty_iface(did, substs) {
+        ty_iface(did, fold_substs(substs, fldop))
       }
-      ty_self(subtys) {
-        ty_self(vec::map(subtys) {|t| fldop(t) })
+      ty_self(substs) {
+        ty_self(fold_substs(substs, fldop))
       }
       ty_rec(fields) {
         let new_fields = vec::map(fields) {|fl|
@@ -864,6 +856,12 @@ fn fold_regions_and_ty(
       ty_class(def_id, substs) {
         ty::mk_class(cx, def_id, fold_substs(substs, fldr, fldt))
       }
+      ty_iface(def_id, substs) {
+        ty::mk_iface(cx, def_id, fold_substs(substs, fldr, fldt))
+      }
+      ty_self(substs) {
+        ty::mk_self(cx, fold_substs(substs, fldr, fldt))
+      }
       ty_res(def_id, t, substs) {
         ty::mk_res(cx, def_id, fldt(t),
                    fold_substs(substs, fldr, fldt))
@@ -1828,10 +1826,8 @@ fn hash_type_structure(st: sty) -> uint {
       }
       ty_var(v) { hash_uint(30u, v.to_uint()) }
       ty_param(pid, did) { hash_def(hash_uint(31u, pid), did) }
-      ty_self(ts) {
-        let mut h = 28u;
-        for ts.each {|t| h = hash_subty(h, t); }
-        h
+      ty_self(substs) {
+        hash_substs(28u, substs)
       }
       ty_type { 32u }
       ty_bot { 34u }
@@ -1850,10 +1846,9 @@ fn hash_type_structure(st: sty) -> uint {
         h
       }
       ty_uniq(mt) { hash_subty(37u, mt.ty) }
-      ty_iface(did, tys) {
+      ty_iface(did, substs) {
         let mut h = hash_def(40u, did);
-        for tys.each {|typ| h = hash_subty(h, typ); }
-        h
+        hash_substs(h, substs)
       }
       ty_opaque_closure_ptr(ck_block) { 41u }
       ty_opaque_closure_ptr(ck_box) { 42u }
@@ -2286,7 +2281,7 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
     if id.crate == ast::local_crate {
         alt cx.items.find(id.node) {
            some(ast_map::node_item(@{node: ast::item_impl(
-              _, some(@{id: id, _}), _, _), _}, _)) {
+              _, _, some(@{id: id, _}), _, _), _}, _)) {
               some(node_id_to_type(cx, id))
            }
            some(ast_map::node_item(@{node: ast::item_class(_, _, _, _, _),
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index fd82061844f..69936c35b60 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -22,7 +22,7 @@ import std::serialization::{serialize_uint, deserialize_uint};
 import std::ufind;
 import vec::each;
 import syntax::print::pprust::*;
-import util::common::indent;
+import util::common::{indent, indenter};
 import std::list;
 import list::{list, nil, cons};
 
@@ -472,7 +472,7 @@ fn get_region_reporting_err(tcx: ty::ctxt,
 }
 
 fn ast_region_to_region<AC: ast_conv, RS: region_scope>(
-    self: AC, rscope: RS, span: span, a_r: ast::region) -> ty::region {
+    self: AC, rscope: RS, span: span, a_r: @ast::region) -> ty::region {
 
     let res = alt a_r.node {
       ast::re_anon { rscope.anon_region() }
@@ -483,40 +483,67 @@ fn ast_region_to_region<AC: ast_conv, RS: region_scope>(
     get_region_reporting_err(self.tcx(), span, res)
 }
 
-fn instantiate<AC: ast_conv, RS: region_scope copy>(
-        self: AC, rscope: RS, sp: span, id: ast::def_id,
-        path_id: ast::node_id, args: [@ast::ty]) -> ty::t {
+fn ast_path_to_substs_and_ty<AC: ast_conv, RS: region_scope copy>(
+    self: AC, rscope: RS, did: ast::def_id,
+    path: @ast::path) -> ty_param_substs_and_ty {
 
-        let tcx = self.tcx();
-        let {bounds, rp, ty} = self.get_item_ty(id);
+    let tcx = self.tcx();
+    let {bounds: decl_bounds, rp: decl_rp, ty: decl_ty} =
+        self.get_item_ty(did);
+
+    // If the type is parameterized by the self region, then replace self
+    // region with the current anon region binding (in other words,
+    // whatever & would get replaced with).
+    let self_r = alt (decl_rp, path.rp) {
+      (ast::rp_none, none) {
+        none
+      }
+      (ast::rp_none, some(_)) {
+        tcx.sess.span_err(
+            path.span,
+            #fmt["No region bound is permitted on %s, \
+                  which is not declared as containing region pointers",
+                 ty::item_path_str(tcx, did)]);
+        none
+      }
+      (ast::rp_self, none) {
+        let res = rscope.anon_region();
+        let r = get_region_reporting_err(self.tcx(), path.span, res);
+        some(r)
+      }
+      (ast::rp_self, some(r)) {
+        some(ast_region_to_region(self, rscope, path.span, r))
+      }
+    };
 
-        // If the type is parameterized by the self region, then replace self
-        // region with the current anon region binding (in other words,
-        // whatever & would get replaced with).
-        let self_r = alt rp {
-          ast::rp_none { none }
-          ast::rp_self {
-            let res = rscope.anon_region();
-            let r = get_region_reporting_err(self.tcx(), sp, res);
-            some(r)
-          }
-        };
+    // Convert the type parameters supplied by the user.
+    if !vec::same_length(*decl_bounds, path.types) {
+        self.tcx().sess.span_fatal(
+            path.span,
+            #fmt["wrong number of type arguments, expected %u but found %u",
+                 (*decl_bounds).len(), path.types.len()]);
+    }
+    let tps = path.types.map { |a_t| ast_ty_to_ty(self, rscope, a_t) };
 
-        // Convert the type parameters supplied by the user.
-        if vec::len(args) != vec::len(*bounds) {
-            tcx.sess.span_fatal(
-                sp, #fmt["wrong number of type arguments, \
-                          expected %u but found %u",
-                         vec::len(*bounds),
-                         vec::len(args)]);
-        }
-        let tps = args.map { |t| ast_ty_to_ty(self, rscope, t) };
+    let substs = {self_r: self_r, tps: tps};
+    {substs: substs, ty: ty::subst(tcx, substs, decl_ty)}
+}
+
+fn ast_path_to_ty<AC: ast_conv, RS: region_scope copy>(
+    self: AC,
+    rscope: RS,
+    did: ast::def_id,
+    path: @ast::path,
+    path_id: ast::node_id) -> ty_param_substs_and_ty {
 
-        // Perform the substitution and store the tps for future ref.
-        let substs = {self_r: self_r, tps: tps};
-        let ty = ty::subst(tcx, substs, ty);
-        write_substs_to_tcx(tcx, path_id, substs.tps);
-        ret ty;
+    // Lookup the polytype of the item and then substitute the provided types
+    // for any type/region parameters.
+    let tcx = self.tcx();
+    let {substs: substs, ty: ty} =
+        ast_path_to_substs_and_ty(self, rscope, did, path);
+    write_ty_to_tcx(tcx, path_id, ty);
+    write_substs_to_tcx(tcx, path_id, substs.tps);
+    ret {substs: substs, ty: ty};
 }
 
 /*
@@ -524,23 +551,25 @@ fn instantiate<AC: ast_conv, RS: region_scope copy>(
   it's bound to a valid iface type. Returns the def_id for the defining
   iface
  */
-fn instantiate_iface_ref(ccx: @crate_ctxt, t: @ast::iface_ref)
-    -> ast::def_id {
+fn instantiate_iface_ref(ccx: @crate_ctxt, t: @ast::iface_ref,
+                         rp: ast::region_param)
+    -> (ast::def_id, ty_param_substs_and_ty) {
+
     alt lookup_def_tcx(ccx.tcx, t.path.span, t.id) {
-       ast::def_ty(t_id) {
-         // tjc: will probably need to refer to
-         // impl or class ty params too
-         instantiate(ccx, empty_rscope, t.path.span, t_id, t.id,
-                     t.path.types);
-         t_id
-       }
-       _ {
-          ccx.tcx.sess.span_fatal(t.path.span,
-                     "can only implement interface types");
-       }
+      ast::def_ty(t_id) {
+        (t_id, ast_path_to_ty(ccx, type_rscope(rp), t_id, t.path, t.id))
+      }
+      _ {
+        ccx.tcx.sess.span_fatal(
+            t.path.span,
+            "can only implement interface types");
+      }
     }
 }
 
+const NO_REGIONS: uint = 1u;
+const NO_TPS: uint = 2u;
+
 // Parses the programmer's textual representation of a type into our
 // internal notion of a type. `getter` is a function that returns the type
 // corresponding to a definition ID:
@@ -553,7 +582,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
         ret {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl};
     }
 
-    fn mk_bounded<AC: ast_conv, RS: region_scope copy>(
+    fn mk_vstore<AC: ast_conv, RS: region_scope copy>(
         self: AC, rscope: RS, a_seq_ty: @ast::ty, vst: ty::vstore) -> ty::t {
 
         let tcx = self.tcx();
@@ -568,39 +597,6 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
             ret ty::mk_estr(tcx, vst);
           }
 
-          ty::ty_enum(_, subst) |
-          ty::ty_class(_, subst) |
-          ty::ty_res(_, _, subst) {
-            // n.b.: This is a hacky abuse of the vstore terminology to also
-            // make it work for region bounds.  The idea is to allow a type
-            // Id/&r where Id is an enum, class, or resource, but not Id/@
-            // etc.  We also do not want to allow Id/&r if the given
-            // enum/class/resource does not define a region parameter.
-            //
-            // Really, these "/&r" bounds ought to be part of the path, like
-            // type parameters.  (In fact, we could generalize to allowing
-            // multiple such bounds someday)
-            alt (subst.self_r, vst) {
-              (some(_), ty::vstore_slice(_)) { /* ok */ }
-              (none, ty::vstore_slice(_)) {
-                tcx.sess.span_err(
-                    a_seq_ty.span,
-                    #fmt["inappropriate bound for %s, \
-                          which is not declared as containing \
-                          region pointers",
-                         ty::ty_sort_str(tcx, seq_ty)]);
-              }
-              (_, _) {
-                tcx.sess.span_err(
-                    a_seq_ty.span,
-                    #fmt["a %s bound is not appropriate for %s",
-                         vstore_to_str(tcx, vst),
-                         ty::ty_sort_str(tcx, seq_ty)]);
-              }
-            }
-            ret seq_ty;
-          }
-
           _ {
             tcx.sess.span_err(
                 a_seq_ty.span,
@@ -611,6 +607,26 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
         }
     }
 
+    fn check_path_args(tcx: ty::ctxt,
+                       path: @ast::path,
+                       flags: uint) {
+        if (flags & NO_TPS) != 0u {
+            if path.types.len() > 0u {
+                tcx.sess.span_err(
+                    path.span,
+                    "Type parameters are not allowed on this type.");
+            }
+        }
+
+        if (flags & NO_REGIONS) != 0u {
+            if path.rp.is_some() {
+                tcx.sess.span_err(
+                    path.span,
+                    "Region parameters are not allowed on this type.");
+            }
+        }
+    }
+
     let tcx = self.tcx();
 
     alt tcx.ast_ty_to_ty_cache.find(ast_ty) {
@@ -665,37 +681,52 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
           some(d) { d }};
         alt a_def {
           ast::def_ty(did) | ast::def_class(did) {
-            instantiate(self, rscope, ast_ty.span, did, id, path.types)
+            ast_path_to_ty(self, rscope, did, path, id).ty
           }
           ast::def_prim_ty(nty) {
             alt nty {
-              ast::ty_bool { ty::mk_bool(tcx) }
-              ast::ty_int(it) { ty::mk_mach_int(tcx, it) }
-              ast::ty_uint(uit) { ty::mk_mach_uint(tcx, uit) }
-              ast::ty_float(ft) { ty::mk_mach_float(tcx, ft) }
-              ast::ty_str { ty::mk_str(tcx) }
+              ast::ty_bool {
+                check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                ty::mk_bool(tcx)
+              }
+              ast::ty_int(it) {
+                check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                ty::mk_mach_int(tcx, it)
+              }
+              ast::ty_uint(uit) {
+                check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                ty::mk_mach_uint(tcx, uit)
+              }
+              ast::ty_float(ft) {
+                check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                ty::mk_mach_float(tcx, ft)
+              }
+              ast::ty_str {
+                check_path_args(tcx, path, NO_TPS);
+                // This is a bit of a hack, but basically str/& needs to be
+                // converted into a vstore:
+                alt path.rp {
+                  none {
+                    ty::mk_str(tcx)
+                  }
+                  some(ast_r) {
+                    let r = ast_region_to_region(self, rscope,
+                                                 ast_ty.span, ast_r);
+                    ty::mk_estr(tcx, ty::vstore_slice(r))
+                  }
+                }
+              }
             }
           }
           ast::def_ty_param(id, n) {
-            if vec::len(path.types) > 0u {
-                tcx.sess.span_err(ast_ty.span, "provided type parameters \
-                                                to a type parameter");
-            }
+            check_path_args(tcx, path, NO_TPS | NO_REGIONS);
             ty::mk_param(tcx, n, id)
           }
           ast::def_self(self_id) {
-            alt check tcx.items.get(self_id) {
-              ast_map::node_item(@{node: ast::item_iface(tps, _), _}, _) {
-                if vec::len(tps) != vec::len(path.types) {
-                    tcx.sess.span_err(ast_ty.span, "incorrect number of \
-                                                    type parameters to \
-                                                    self type");
-                }
-                ty::mk_self(tcx, vec::map(path.types, {|ast_ty|
-                    ast_ty_to_ty(self, rscope, ast_ty)
-                }))
-              }
-            }
+            let {substs, ty: _} =
+                ast_path_to_substs_and_ty(self, rscope,
+                                          local_def(self_id), path);
+            ty::mk_self(tcx, substs)
           }
           _ {
             tcx.sess.span_fatal(ast_ty.span,
@@ -705,16 +736,16 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
       }
       ast::ty_vstore(a_t, ast::vstore_slice(a_r)) {
         let r = ast_region_to_region(self, rscope, ast_ty.span, a_r);
-        mk_bounded(self, in_anon_rscope(rscope, r), a_t, ty::vstore_slice(r))
+        mk_vstore(self, in_anon_rscope(rscope, r), a_t, ty::vstore_slice(r))
       }
       ast::ty_vstore(a_t, ast::vstore_uniq) {
-        mk_bounded(self, rscope, a_t, ty::vstore_uniq)
+        mk_vstore(self, rscope, a_t, ty::vstore_uniq)
       }
       ast::ty_vstore(a_t, ast::vstore_box) {
-        mk_bounded(self, rscope, a_t, ty::vstore_box)
+        mk_vstore(self, rscope, a_t, ty::vstore_box)
       }
       ast::ty_vstore(a_t, ast::vstore_fixed(some(u))) {
-        mk_bounded(self, rscope, a_t, ty::vstore_fixed(u))
+        mk_vstore(self, rscope, a_t, ty::vstore_fixed(u))
       }
       ast::ty_vstore(_, ast::vstore_fixed(none)) {
         tcx.sess.span_bug(
@@ -790,7 +821,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
       }
       ast::item_res(decl, tps, _, _, _, rp) {
         let {bounds, substs} = mk_substs(ccx, tps, rp);
-        let t_arg = ty_of_arg(ccx, empty_rscope, decl.inputs[0]);
+        let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
         let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs);
         let t_res = {bounds: bounds, rp: rp, ty: t};
         tcx.tcache.insert(local_def(it.id), t_res);
@@ -804,11 +835,10 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
         tcx.tcache.insert(local_def(it.id), tpt);
         ret tpt;
       }
-      ast::item_iface(tps, ms) {
-        let {bounds, params} = mk_ty_params(ccx, tps);
-        let t = ty::mk_iface(tcx, local_def(it.id), params);
-        // NDM iface/impl regions
-        let tpt = {bounds: bounds, rp: ast::rp_none, ty: t};
+      ast::item_iface(tps, rp, ms) {
+        let {bounds, substs} = mk_substs(ccx, tps, rp);
+        let t = ty::mk_iface(tcx, local_def(it.id), substs);
+        let tpt = {bounds: bounds, rp: rp, ty: t};
         tcx.tcache.insert(local_def(it.id), tpt);
         ret tpt;
       }
@@ -819,7 +849,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
           tcx.tcache.insert(local_def(it.id), tpt);
           ret tpt;
       }
-      ast::item_impl(_, _, _, _) | ast::item_mod(_) |
+      ast::item_impl(*) | ast::item_mod(_) |
       ast::item_native_mod(_) { fail; }
     }
 }
@@ -1040,15 +1070,19 @@ fn ty_param_bounds(ccx: @crate_ctxt,
 fn ty_of_method(ccx: @crate_ctxt,
                 m: @ast::method,
                 rp: ast::region_param) -> ty::method {
-    {ident: m.ident, tps: ty_param_bounds(ccx, m.tps),
+    {ident: m.ident,
+     tps: ty_param_bounds(ccx, m.tps),
      fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, m.decl),
-     purity: m.decl.purity, privacy: m.privacy}
+     purity: m.decl.purity,
+     privacy: m.privacy}
 }
 
-fn ty_of_ty_method(self: @crate_ctxt, m: ast::ty_method) -> ty::method {
+fn ty_of_ty_method(self: @crate_ctxt,
+                   m: ast::ty_method,
+                   rp: ast::region_param) -> ty::method {
     {ident: m.ident,
      tps: ty_param_bounds(self, m.tps),
-     fty: ty_of_fn_decl(self, empty_rscope, ast::proto_bare, m.decl),
+     fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.decl),
      // assume public, because this is only invoked on iface methods
      purity: m.decl.purity, privacy: ast::pub}
 }
@@ -1180,6 +1214,14 @@ impl methods for @fn_ctxt {
                  self.ty_to_str(a),
                  ty::type_err_to_str(self.ccx.tcx, err)]);
     }
+
+    fn mk_subty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
+        infer::mk_subty(self.infcx, sub, sup)
+    }
+
+    fn mk_eqty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
+        infer::mk_eqty(self.infcx, sub, sup)
+    }
 }
 
 fn mk_ty_params(ccx: @crate_ctxt, atps: [ast::ty_param])
@@ -1207,7 +1249,7 @@ fn mk_substs(ccx: @crate_ctxt, atps: [ast::ty_param], rp: ast::region_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::substs,
                        self_ty: ty::t) -> ty::t {
 
     if impl_m.tps != if_m.tps {
@@ -1234,11 +1276,14 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
         let impl_fty = ty::mk_fn(tcx, {inputs: auto_modes with impl_m.fty});
 
         // Add dummy substs for the parameters of the impl method
-        let substs = substs + vec::from_fn(vec::len(*if_m.tps), {|i|
-            ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0})
-        });
+        let substs = {
+            self_r: substs.self_r,
+            tps: substs.tps + vec::from_fn(vec::len(*if_m.tps), {|i|
+                ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0})
+            })
+        };
         let mut if_fty = ty::mk_fn(tcx, if_m.fty);
-        if_fty = ty::subst_tps(tcx, substs, if_fty);
+        if_fty = ty::subst(tcx, substs, if_fty);
         if_fty = fixup_self_full(tcx, if_fty, substs, self_ty, impl_tps);
         require_same_types(
             tcx, sp, impl_fty, if_fty,
@@ -1253,38 +1298,45 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
 // 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_full(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t],
+fn fixup_self_full(cx: ty::ctxt, mty: ty::t, m_substs: ty::substs,
                    selfty: ty::t, impl_n_tps: uint) -> ty::t {
 
     if !ty::type_has_vars(mty) { ret mty; }
 
     ty::fold_ty(cx, mty) {|t|
         alt ty::get(t).struct {
-          ty::ty_self(tps) if vec::len(tps) == 0u { selfty }
-          ty::ty_self(tps) {
+          ty::ty_self(substs) if ty::substs_is_noop(substs) {
+            selfty
+          }
+          ty::ty_self(substs) {
             // Move the substs into the type param system of the
             // context.
-            let mut substs = vec::map(tps) {|t|
+            let mut substs_tps = vec::map(substs.tps) {|t|
                 let f = fixup_self_full(cx, t, m_substs, selfty, impl_n_tps);
-                ty::subst_tps(cx, m_substs, f)
+                ty::subst(cx, m_substs, f)
             };
 
             // 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})];
+            while vec::len(substs_tps) < impl_n_tps {
+                substs_tps += [ty::mk_param(cx, substs_tps.len(),
+                                            {crate: 0, node: 0})];
             }
 
             // And for method type parameters.
-            let method_n_tps =
-                (vec::len(m_substs) - vec::len(tps)) as int;
+            let method_n_tps = (
+                m_substs.tps.len() - substs_tps.len()) as int;
             if method_n_tps > 0 {
-                substs += vec::tailn(m_substs, vec::len(m_substs)
-                                     - (method_n_tps as uint));
+                substs_tps += vec::tailn(
+                    m_substs.tps,
+                    m_substs.tps.len() - (method_n_tps as uint));
             }
 
             // And then instantiate the self type using all those.
-            ty::subst_tps(cx, substs, selfty)
+            let substs_1 = {
+                self_r: substs.self_r,
+                tps: substs_tps
+            };
+            ty::subst(cx, substs_1, selfty)
           }
           _ {
               t
@@ -1298,27 +1350,26 @@ fn fixup_self_full(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t],
 // 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_param(fcx: @fn_ctxt, mty: ty::t, m_substs: [ty::t],
+fn fixup_self_param(fcx: @fn_ctxt, mty: ty::t, m_substs: ty::substs,
                     selfty: ty::t, sp: span) -> ty::t {
     if !ty::type_has_vars(mty) { ret mty; }
 
     let tcx = fcx.ccx.tcx;
     ty::fold_ty(tcx, mty) {|t|
         alt ty::get(t).struct {
-          ty::ty_self(tps) if vec::len(tps) == 0u { selfty }
-          ty::ty_self(tps) {
-            // Move the substs into the type param system of the
-            // context.
-            let mut substs = vec::map(tps) {|t|
+          ty::ty_self(substs) if ty::substs_is_noop(substs) {
+            selfty
+          }
+          ty::ty_self(substs) {
+            // Move the substs into the type param system of the context.
+            let tps_p = vec::map(substs.tps) {|t|
                 let f = fixup_self_param(fcx, t, m_substs, selfty, sp);
-                ty::subst_tps(tcx, m_substs, f)
+                ty::subst(tcx, m_substs, f)
             };
-
-            // Simply ensure that the type parameters for the self
-            // type match the context.
-            vec::iter2(substs, m_substs) {|s, ms|
-                demand::suptype(fcx, sp, s, ms);
-            }
+            let substs_p = {self_r: substs.self_r, tps: tps_p};
+            let self_p = ty::mk_self(tcx, substs_p);
+            let m_self = ty::mk_self(tcx, m_substs);
+            demand::suptype(fcx, sp, m_self, self_p);
             selfty
           }
           _ { t }
@@ -1392,9 +1443,9 @@ mod collect {
 
         let tcx = ccx.tcx;
         alt check tcx.items.get(id) {
-          ast_map::node_item(@{node: ast::item_iface(_, ms), _}, _) {
+          ast_map::node_item(@{node: ast::item_iface(_, rp, ms), _}, _) {
               store_methods::<ast::ty_method>(ccx, id, ms) {|m|
-                  ty_of_ty_method(ccx, m)
+                  ty_of_ty_method(ccx, m, rp)
               };
           }
           ast_map::node_item(@{node: ast::item_class(_,_,its,_,rp), _}, _) {
@@ -1412,52 +1463,45 @@ mod collect {
                                    tps: [ast::ty_param],
                                    rp: ast::region_param,
                                    selfty: ty::t,
-                                   t: @ast::iface_ref,
-                                   ms: [@ast::method]) -> ast::def_id {
+                                   a_ifacety: @ast::iface_ref,
+                                   ms: [@ast::method]) {
 
         let tcx = ccx.tcx;
         let i_bounds = ty_param_bounds(ccx, tps);
         let my_methods = convert_methods(ccx, ms, rp, i_bounds, selfty);
-        let did = instantiate_iface_ref(ccx, t);
-        // not sure whether it's correct to use empty_rscope
-        // -- tjc
-        let tys = vec::map(t.path.types,
-                           {|t| ccx.to_ty(empty_rscope,t)});
-        // Store the iface type in the type node
-        write_ty_to_tcx(tcx, t.id, ty::mk_iface(ccx.tcx, did, tys));
+        let (did, tpt) = instantiate_iface_ref(ccx, a_ifacety, rp);
         if did.crate == ast::local_crate {
             ensure_iface_methods(ccx, did.node);
         }
         for vec::each(*ty::iface_methods(tcx, did)) {|if_m|
-           alt vec::find(my_methods,
-              {|m| if_m.ident == m.mty.ident}) {
-             some({mty: m, id, span}) {
-                 if m.purity != if_m.purity {
-                         ccx.tcx.sess.span_err(
-                           span, #fmt["method `%s`'s purity \
-                                        not match the iface method's \
-                                        purity", m.ident]);
-                 }
-                 let mt = compare_impl_method(
-                        ccx.tcx, span, m, vec::len(tps),
-                        if_m, tys, selfty);
-                 let old = tcx.tcache.get(local_def(id));
-                 if old.ty != mt {
-                        tcx.tcache.insert(
-                            local_def(id),
-                            {bounds: old.bounds,
-                             rp: old.rp,
-                             ty: mt});
-                        write_ty_to_tcx(tcx, id, mt);
-                    }
-                  }
-             none {
-               tcx.sess.span_err(t.path.span, "missing method `" +
-                                      if_m.ident + "`");
-             }
-           } // alt
+            alt vec::find(my_methods, {|m| if_m.ident == m.mty.ident}) {
+              some({mty: m, id, span}) {
+                if m.purity != if_m.purity {
+                    ccx.tcx.sess.span_err(
+                        span, #fmt["method `%s`'s purity \
+                                    not match the iface method's \
+                                    purity", m.ident]);
+                }
+                let mt = compare_impl_method(
+                    ccx.tcx, span, m, vec::len(tps),
+                    if_m, tpt.substs, selfty);
+                let old = tcx.tcache.get(local_def(id));
+                if old.ty != mt {
+                    tcx.tcache.insert(
+                        local_def(id),
+                        {bounds: old.bounds,
+                         rp: old.rp,
+                         ty: mt});
+                    write_ty_to_tcx(tcx, id, mt);
+                }
+              }
+              none {
+                tcx.sess.span_err(
+                    a_ifacety.path.span,
+                    #fmt["missing method `%s`", if_m.ident]);
+              }
+            } // alt
         } // |if_m|
-        did
     } // fn
 
     fn convert_class_item(ccx: @crate_ctxt,
@@ -1510,26 +1554,25 @@ mod collect {
             get_enum_variant_types(ccx, tpt.ty, variants,
                                    ty_params, rp);
           }
-          ast::item_impl(tps, ifce, selfty, ms) {
+          ast::item_impl(tps, rp, ifce, selfty, ms) {
             let i_bounds = ty_param_bounds(ccx, tps);
-            // NDM iface/impl regions
-            let selfty = ccx.to_ty(empty_rscope, selfty);
+            let selfty = ccx.to_ty(type_rscope(rp), selfty);
             write_ty_to_tcx(tcx, it.id, selfty);
             tcx.tcache.insert(local_def(it.id),
                               {bounds: i_bounds,
-                               rp: ast::rp_none, // NDM iface/impl regions
+                               rp: rp,
                                ty: selfty});
             alt ifce {
               some(t) {
-                  check_methods_against_iface(
-                    ccx, tps, ast::rp_none, // NDM iface/impl regions
+                check_methods_against_iface(
+                    ccx, tps, rp,
                     selfty, t, ms);
               }
               _ {
                 // Still have to do this to write method types
                 // into the table
                 convert_methods(
-                    ccx, ms, ast::rp_none, // NDM iface/impl regions
+                    ccx, ms, rp,
                     i_bounds, selfty);
               }
             }
@@ -1555,15 +1598,17 @@ mod collect {
             write_ty_to_tcx(tcx, ctor_id, t_ctor);
             tcx.tcache.insert(local_def(ctor_id),
                               {bounds: bounds,
-                               rp: ast::rp_none,
+                               rp: rp,
                                ty: t_ctor});
             tcx.tcache.insert(def_id, {bounds: bounds,
-                                       rp: ast::rp_none,
+                                       rp: rp,
                                        ty: t_res});
             write_ty_to_tcx(tcx, dtor_id, t_dtor);
           }
-          ast::item_iface(_, ms) {
+          ast::item_iface(*) {
             let tpt = ty_of_item(ccx, it);
+            #debug["item_iface(it.id=%d, tpt.ty=%s)",
+                   it.id, ty_to_str(tcx, tpt.ty)];
             write_ty_to_tcx(tcx, it.id, tpt.ty);
             ensure_iface_methods(ccx, it.id);
           }
@@ -1581,7 +1626,7 @@ mod collect {
             write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
             tcx.tcache.insert(local_def(ctor.node.id),
                               {bounds: tpt.bounds,
-                               rp: ast::rp_none, // NDM self->anon
+                               rp: ast::rp_none,
                                ty: t_ctor});
             ensure_iface_methods(ccx, it.id);
             /* FIXME: check for proper public/privateness */
@@ -1605,15 +1650,14 @@ mod collect {
             that it claims to implement.
             */
             for ifaces.each { |ifce|
-                let t_id = check_methods_against_iface(ccx, tps, rp, selfty,
-                                                       ifce, methods);
+                check_methods_against_iface(ccx, tps, rp, selfty,
+                                            ifce, methods);
+                let t = ty::node_id_to_type(tcx, ifce.id);
+
                 // FIXME: This assumes classes only implement
                 // non-parameterized ifaces. add a test case for
                 // a class implementing a parameterized iface.
                 // -- tjc (#1726)
-                let t = ty::mk_iface(tcx, t_id, []);
-                write_ty_to_tcx(tcx, ifce.id, t);
-                // FIXME: likewise, assuming no bounds -- tjc
                 tcx.tcache.insert(local_def(ifce.id), no_params(t));
             }
           }
@@ -1647,15 +1691,6 @@ mod collect {
 }
 
 
-// Type unification
-mod unify {
-    fn unify(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) ->
-        result<(), ty::type_err> {
-        ret infer::mk_subty(fcx.infcx, actual, expected);
-    }
-}
-
-
 // FIXME This is almost a duplicate of ty::type_autoderef, with structure_of
 // instead of ty::struct.
 fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t {
@@ -1732,6 +1767,7 @@ mod demand {
     fn suptype(fcx: @fn_ctxt, sp: span,
               expected: ty::t, actual: ty::t) {
 
+        // n.b.: order of actual, expected is reversed
         alt infer::mk_subty(fcx.infcx, actual, expected) {
           result::ok(()) { /* ok */ }
           result::err(err) {
@@ -1740,6 +1776,17 @@ mod demand {
         }
     }
 
+    fn eqtype(fcx: @fn_ctxt, sp: span,
+              expected: ty::t, actual: ty::t) {
+
+        alt infer::mk_eqty(fcx.infcx, actual, expected) {
+          result::ok(()) { /* ok */ }
+          result::err(err) {
+            fcx.report_mismatched_types(sp, expected, actual, err);
+          }
+        }
+    }
+
     // Checks that the type `actual` can be assigned to `expected`.
     fn assign(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) {
         let expr_ty = fcx.expr_ty(expr);
@@ -1755,7 +1802,7 @@ mod demand {
 
 // Returns true if the two types unify and false if they don't.
 fn are_compatible(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) -> bool {
-    alt unify::unify(fcx, expected, actual) {
+    alt fcx.mk_eqty(expected, actual) {
       result::ok(_) { ret true; }
       result::err(_) { ret false; }
     }
@@ -2390,14 +2437,14 @@ fn check_expr(fcx: @fn_ctxt, expr: @ast::expr,
 fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
     let tcx = fcx.ccx.tcx;
 
-    let {n_tps, raw_ty} = if did.crate == ast::local_crate {
+    let {n_tps, rp, raw_ty} = if did.crate == ast::local_crate {
         alt check tcx.items.find(did.node) {
-          some(ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
-                                _}, _)) {
+          some(ast_map::node_item(@{node: ast::item_impl(ts, rp, _, st, _),
+                                  _}, _)) {
             {n_tps: ts.len(),
-             raw_ty: fcx.to_ty(st)}
+             rp: rp,
+             raw_ty: fcx.ccx.to_ty(type_rscope(rp), st)}
           }
-          // Node doesn't map to an impl. It might map to a class.
           some(ast_map::node_item(@{node: ast::item_class(ts,
                                     _,_,_,rp), id: class_id, _},_)) {
               /* If the impl is a class, the self ty is just the class ty
@@ -2405,6 +2452,7 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
                  we substitute in fresh vars for them)
                */
               {n_tps: ts.len(),
+               rp: rp,
                raw_ty: ty::mk_class(tcx, local_def(class_id),
                       {self_r: alt rp {
                           ast::rp_self { some(fcx.next_region_var()) }
@@ -2417,11 +2465,16 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
     } else {
         let ity = ty::lookup_item_type(tcx, did);
         {n_tps: vec::len(*ity.bounds),
+         rp: ity.rp,
          raw_ty: ity.ty}
     };
 
-    let self_r = none; // NDM iface/impl regions
+    let self_r = alt rp {
+      ast::rp_none { none }
+      ast::rp_self { some(fcx.next_region_var()) }
+    };
     let tps = fcx.next_ty_vars(n_tps);
+
     let substs = {self_r: self_r, tps: tps};
     let substd_ty = ty::subst(tcx, substs, raw_ty);
     {substs: substs, ty: substd_ty}
@@ -2449,8 +2502,8 @@ impl methods for lookup {
           ty::ty_param(n, did) {
             self.method_from_param(n, did)
           }
-          ty::ty_iface(did, tps) {
-            self.method_from_iface(did, tps)
+          ty::ty_iface(did, substs) {
+            self.method_from_iface(did, substs)
           }
           ty::ty_class(did, substs) {
             self.method_from_class(did, substs)
@@ -2473,11 +2526,11 @@ impl methods for lookup {
         let mut iface_bnd_idx = 0u; // count only iface bounds
         let bounds = tcx.ty_param_bounds.get(did.node);
         for vec::each(*bounds) {|bound|
-            let (iid, bound_tps) = alt bound {
+            let (iid, bound_substs) = alt bound {
               ty::bound_copy | ty::bound_send { cont; /* ok */ }
               ty::bound_iface(bound_t) {
                 alt check ty::get(bound_t).struct {
-                  ty::ty_iface(i, tps) { (i, tps) }
+                  ty::ty_iface(i, substs) { (i, substs) }
                 }
               }
             };
@@ -2490,9 +2543,6 @@ impl methods for lookup {
               }
 
               some(pos) {
-                let bound_substs = { // NDM iface/impl regions
-                    self_r: none, tps: bound_tps
-                };
                 ret some(self.write_mty_from_m(
                     some(self.self_ty), bound_substs, ifce_methods[pos],
                     method_param(iid, pos, n, iface_bnd_idx)));
@@ -2503,7 +2553,7 @@ impl methods for lookup {
     }
 
     fn method_from_iface(
-        did: ast::def_id, iface_tps: [ty::t]) -> option<method_origin> {
+        did: ast::def_id, iface_substs: ty::substs) -> option<method_origin> {
 
         let ms = *ty::iface_methods(self.tcx(), did);
         for ms.eachi {|i, m|
@@ -2525,10 +2575,6 @@ impl methods for lookup {
                      boxed iface");
             }
 
-            let iface_substs = { // NDM iface/impl regions
-                self_r: none, tps: iface_tps
-            };
-
             ret some(self.write_mty_from_m(
                 none, iface_substs, m,
                 method_iface(did, i)));
@@ -2565,6 +2611,12 @@ impl methods for lookup {
     }
 
     fn ty_from_did(did: ast::def_id) -> ty::t {
+        alt check ty::get(ty::lookup_item_type(self.tcx(), did).ty).struct {
+          ty::ty_fn(fty) {
+            ty::mk_fn(self.tcx(), {proto: ast::proto_box with fty})
+          }
+        }
+        /*
         if did.crate == ast::local_crate {
             alt check self.tcx().items.get(did.node) {
               ast_map::node_method(m, _, _) {
@@ -2580,6 +2632,7 @@ impl methods for lookup {
               }
             }
         }
+        */
     }
 
     fn method_from_scope() -> option<method_origin> {
@@ -2608,7 +2661,7 @@ impl methods for lookup {
 
                     // if we can assign the caller to the callee, that's a
                     // potential match.  Collect those in the vector.
-                    alt unify::unify(self.fcx, self_ty, ty) {
+                    alt self.fcx.mk_subty(ty, self_ty) {
                       result::err(_) { /* keep looking */ }
                       result::ok(_) {
                         results += [(self_substs, m.n_tps, m.did)];
@@ -2696,7 +2749,7 @@ impl methods for lookup {
         if has_self && !option::is_none(self_ty_sub) {
             let fty = self.fcx.node_ty(self.node_id);
             let fty = fixup_self_param(
-                self.fcx, fty, all_substs.tps, self_ty_sub.get(),
+                self.fcx, fty, all_substs, self_ty_sub.get(),
                 self.expr.span);
             self.fcx.write_ty(self.node_id, fty);
         }
@@ -3492,9 +3545,13 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         let t_1 = fcx.to_ty(t);
         let t_e = fcx.expr_ty(e);
 
+        #debug["t_1=%s", fcx.ty_to_str(t_1)];
+        #debug["t_e=%s", fcx.ty_to_str(t_e)];
+
         alt ty::get(t_1).struct {
           // This will be looked up later on
-          ty::ty_iface(_, _) {}
+          ty::ty_iface(*) {}
+
           _ {
             if ty::type_is_nil(t_e) {
                 tcx.sess.span_err(expr.span, "cast from nil: " +
@@ -4075,7 +4132,8 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) {
                     ast::carg_ident(i) {
                       if i < num_args {
                           let p = @{span: a.span, global: false,
-                                    idents: [args[i].ident], types: []};
+                                    idents: [args[i].ident],
+                                    rp: none, types: []};
                           let arg_occ_node_id =
                               fcx.ccx.tcx.sess.next_node_id();
                           fcx.ccx.tcx.def_map.insert
@@ -4356,10 +4414,8 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
         check_instantiable(ccx.tcx, it.span, it.id);
         check_bare_fn(ccx, decl, body, dtor_id, none);
       }
-      ast::item_impl(tps, _, ty, ms) {
-        let self_ty = ccx.to_ty(empty_rscope, ty); // NDM iface/impl regions
-        let self_region = ty::re_free(it.id, ty::br_self);
-        let self_ty = replace_self_region(ccx.tcx, self_region, self_ty);
+      ast::item_impl(tps, rp, _, ty, ms) {
+        let self_ty = ccx.to_ty(type_rscope(rp), ty);
         for ms.each {|m| check_method(ccx, m, self_ty);}
       }
       ast::item_class(tps, ifaces, members, ctor, rp) {
@@ -4459,15 +4515,15 @@ mod vtable {
     }
 
     fn lookup_vtables(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
-                      bounds: @[ty::param_bounds], tys: [ty::t],
+                      bounds: @[ty::param_bounds], substs: ty::substs,
                       allow_unsafe: bool) -> vtable_res {
         let tcx = fcx.ccx.tcx;
         let mut result = [], i = 0u;
-        for tys.each {|ty|
+        for substs.tps.each {|ty|
             for vec::each(*bounds[i]) {|bound|
                 alt bound {
                   ty::bound_iface(i_ty) {
-                    let i_ty = ty::subst_tps(tcx, tys, i_ty);
+                    let i_ty = ty::subst(tcx, substs, i_ty);
                     result += [lookup_vtable(fcx, isc, sp, ty, i_ty,
                                              allow_unsafe)];
                   }
@@ -4479,6 +4535,22 @@ mod vtable {
         @result
     }
 
+    fn fixup_substs(fcx: @fn_ctxt, sp: span,
+                    substs: ty::substs) -> ty::substs {
+        let tcx = fcx.ccx.tcx;
+        // use a dummy type just to package up the substs that need fixing up
+        let t = ty::mk_self(tcx, substs);
+        let t_f = fixup_ty(fcx, sp, t);
+        alt check ty::get(t_f).struct {
+          ty::ty_self(substs_f) { substs_f }
+        }
+    }
+
+    fn relate_iface_tys(fcx: @fn_ctxt, sp: span,
+                        exp_iface_ty: ty::t, act_iface_ty: ty::t) {
+        demand::suptype(fcx, sp, exp_iface_ty, act_iface_ty)
+    }
+
     /*
       Look up the vtable to use when treating an item of type <t>
       as if it has type <iface_ty>
@@ -4486,29 +4558,39 @@ mod vtable {
     fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
                      ty: ty::t, iface_ty: ty::t, allow_unsafe: bool)
         -> vtable_origin {
+
+        #debug["lookup_vtable(ty=%s, iface_ty=%s)",
+               fcx.ty_to_str(ty), fcx.ty_to_str(iface_ty)];
+        let _i = indenter();
+
         let tcx = fcx.ccx.tcx;
-        let (iface_id, iface_tps) = alt check ty::get(iface_ty).struct {
-            ty::ty_iface(did, tps) { (did, tps) }
+        let (iface_id, iface_substs) = alt check ty::get(iface_ty).struct {
+            ty::ty_iface(did, substs) { (did, substs) }
         };
         let ty = fixup_ty(fcx, sp, ty);
         alt ty::get(ty).struct {
           ty::ty_param(n, did) {
             let mut n_bound = 0u;
-            for vec::each(*tcx.ty_param_bounds.get(did.node)) {|bound|
+            for vec::each(*tcx.ty_param_bounds.get(did.node)) { |bound|
                 alt bound {
+                  ty::bound_send | ty::bound_copy { /* ignore */ }
                   ty::bound_iface(ity) {
                     alt check ty::get(ity).struct {
-                      ty::ty_iface(idid, _) {
-                        if iface_id == idid { ret vtable_param(n, n_bound); }
+                      ty::ty_iface(idid, substs) {
+                        if iface_id == idid {
+                            relate_iface_tys(fcx, sp, iface_ty, ity);
+                            ret vtable_param(n, n_bound);
+                        }
                       }
                     }
                     n_bound += 1u;
                   }
-                  _ {}
                 }
             }
           }
-          ty::ty_iface(did, tps) if iface_id == did {
+
+          ty::ty_iface(did, substs) if iface_id == did {
+            relate_iface_tys(fcx, sp, iface_ty, ty);
             if !allow_unsafe {
                 for vec::each(*ty::iface_methods(tcx, did)) {|m|
                     if ty::type_has_vars(ty::mk_fn(tcx, m.fty)) {
@@ -4523,50 +4605,59 @@ mod vtable {
                     }
                 }
             }
-            ret vtable_iface(did, tps);
+            ret vtable_iface(did, substs.tps);
           }
+
           _ {
+            let mut found = [];
+
             for list::each(isc) {|impls|
-                let mut found = none;
                 for vec::each(*impls) {|im|
-                    /* What iface does this item implement? */
-                    let match = alt ty::impl_iface(tcx, im.did) {
-                      some(ity) {
-                        alt check ty::get(ity).struct {
-                        /* Does it match the one we're searching for? */
-                          ty::ty_iface(id, _) { id == iface_id }
-                        }
-                      }
-                      _ { false }
+                    // find the iface that the impl is an impl of (if any)
+                    let of_ty = alt ty::impl_iface(tcx, im.did) {
+                      some(of_ty) { of_ty }
+                      _ { cont; }
                     };
-                    /* Found a matching iface */
-                    if match {
-                        let {substs: substs, ty: self_ty} =
-                            impl_self_ty(fcx, im.did);
-                        let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
-                        alt unify::unify(fcx, ty, self_ty) {
-                          result::ok(_) {
-                            if option::is_some(found) {
-                                tcx.sess.span_err(
-                                    sp, "multiple applicable implementations \
-                                         in scope");
-                            } else {
-                                let vars = substs.tps;
-                                connect_iface_tps(fcx, sp, vars,
-                                                  iface_tps, im.did);
-                                let params = vec::map(vars, {|t|
-                                    fixup_ty(fcx, sp, t)});
-                                let subres = lookup_vtables(
-                                    fcx, isc, sp, im_bs, params, false);
-                                found = some(vtable_static(im.did, params,
-                                                           subres));
-                            }
-                          }
-                          result::err(_) {}
-                        }
+
+                    // it must have the same id as the expected one
+                    alt ty::get(of_ty).struct {
+                      ty::ty_iface(id, _) if id != iface_id { cont; }
+                      _ { /* ok */ }
+                    }
+
+                    // check whether the type unifies with the type
+                    // that the impl is for, and continue if not
+                    let {substs: substs, ty: for_ty} =
+                        impl_self_ty(fcx, im.did);
+                    let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
+                    alt fcx.mk_subty(ty, for_ty) {
+                      result::err(_) { cont; }
+                      result::ok(()) { }
                     }
+
+                    // check that desired iface type unifies
+                    let of_ty = ty::subst(tcx, substs, of_ty);
+                    relate_iface_tys(fcx, sp, iface_ty, of_ty);
+
+                    // recursively process the bounds
+                    let iface_tps = iface_substs.tps;
+                    let substs_f = fixup_substs(fcx, sp, substs);
+                    connect_iface_tps(fcx, sp, substs_f.tps,
+                                      iface_tps, im.did);
+                    let subres = lookup_vtables(fcx, isc, sp,
+                                                im_bs, substs_f, false);
+                    found += [vtable_static(im.did, substs_f.tps, subres)];
+                }
+
+                alt found.len() {
+                  0u { /* fallthrough */ }
+                  1u { ret found[0]; }
+                  _ {
+                    fcx.ccx.tcx.sess.span_err(
+                        sp, "multiple applicable methods in scope");
+                    ret found[0];
+                  }
                 }
-                alt found { some(x) { ret x; } _ {} }
             }
           }
         }
@@ -4597,8 +4688,8 @@ mod vtable {
         let ity = option::get(ty::impl_iface(tcx, impl_did));
         let iface_ty = ty::subst_tps(tcx, impl_tys, ity);
         alt check ty::get(iface_ty).struct {
-          ty::ty_iface(_, tps) {
-            vec::iter2(tps, iface_tys,
+          ty::ty_iface(_, substs) {
+            vec::iter2(substs.tps, iface_tys,
                        {|a, b| demand::suptype(fcx, sp, a, b);});
           }
         }
@@ -4607,26 +4698,25 @@ mod vtable {
     fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
         let cx = fcx.ccx;
         alt ex.node {
-          ast::expr_path(_) {
+          ast::expr_path(*) {
             alt fcx.opt_node_ty_substs(ex.id) {
               some(substs) {
-                let ts = substs.tps; // NDM regions for iface/impls
                 let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
                 let item_ty = ty::lookup_item_type(cx.tcx, did);
                 if has_iface_bounds(*item_ty.bounds) {
                     let impls = cx.impl_map.get(ex.id);
                     cx.vtable_map.insert(ex.id, lookup_vtables(
                         fcx, impls, ex.span,
-                        item_ty.bounds, ts, false));
+                        item_ty.bounds, substs, false));
                 }
               }
               _ {}
             }
           }
           // Must resolve bounds on methods with bounded params
-          ast::expr_field(_, _, _) | ast::expr_binary(_, _, _) |
-          ast::expr_unary(_, _) | ast::expr_assign_op(_, _, _) |
-          ast::expr_index(_, _) {
+          ast::expr_field(*) | ast::expr_binary(*) |
+          ast::expr_unary(*) | ast::expr_assign_op(*) |
+          ast::expr_index(*) {
             alt cx.method_map.find(ex.id) {
               some(method_static(did)) {
                 let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
@@ -4635,11 +4725,10 @@ mod vtable {
                       ast::expr_field(_, _, _) { ex.id }
                       _ { ast_util::op_expr_callee_id(ex) }
                     };
-                    // NDM iface/impl regions
-                    let ts = fcx.node_ty_substs(callee_id).tps;
+                    let substs = fcx.node_ty_substs(callee_id);
                     let iscs = cx.impl_map.get(ex.id);
                     cx.vtable_map.insert(callee_id, lookup_vtables(
-                        fcx, iscs, ex.span, bounds, ts, false));
+                        fcx, iscs, ex.span, bounds, substs, false));
                 }
               }
               _ {}
@@ -4648,7 +4737,7 @@ mod vtable {
           ast::expr_cast(src, _) {
             let target_ty = fcx.expr_ty(ex);
             alt ty::get(target_ty).struct {
-              ty::ty_iface(_, _) {
+              ty::ty_iface(*) {
                /* Casting to an interface type.
                   Look up all impls for the cast expr...
                */
diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs
index 1a27bbdff84..227dc0c8645 100644
--- a/src/rustc/util/ppaux.rs
+++ b/src/rustc/util/ppaux.rs
@@ -134,12 +134,10 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
       some(def_id) {
         let cs = ast_map::path_to_str(ty::item_path(cx, def_id));
         ret alt ty::get(typ).struct {
-          ty_enum(_, substs) | ty_res(_, _, substs) | ty_class(_, substs) {
+          ty_enum(_, substs) | ty_res(_, _, substs) | ty_class(_, substs) |
+          ty_iface(_, substs) {
             parameterized(cx, cs, substs.self_r, substs.tps)
           }
-          ty_iface(_, tps) {
-            parameterized(cx, cs, none, tps)
-          }
           _ { cs }
         };
       }
@@ -159,7 +157,6 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
       ty_float(ast::ty_f) { "float" }
       ty_float(t) { ast_util::float_ty_to_str(t) }
       ty_str { "str" }
-      ty_self(ts) { parameterized(cx, "self", none, ts) }
       ty_box(tm) { "@" + mt_to_str(cx, tm) }
       ty_uniq(tm) { "~" + mt_to_str(cx, tm) }
       ty_ptr(tm) { "*" + mt_to_str(cx, tm) }
@@ -191,15 +188,18 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
       ty_param(id, _) {
         "'" + str::from_bytes([('a' as u8) + (id as u8)])
       }
+      ty_self(substs) {
+        parameterized(cx, "self", substs.self_r, substs.tps)
+      }
       ty_enum(did, substs) | ty_res(did, _, substs) | ty_class(did, substs) {
         let path = ty::item_path(cx, did);
         let base = ast_map::path_to_str(path);
         parameterized(cx, base, substs.self_r, substs.tps)
       }
-      ty_iface(did, tps) {
+      ty_iface(did, substs) {
         let path = ty::item_path(cx, did);
         let base = ast_map::path_to_str(path);
-        parameterized(cx, base, none, tps)
+        parameterized(cx, base, substs.self_r, substs.tps)
       }
       ty_evec(mt, vs) {
         #fmt["[%s]/%s", mt_to_str(cx, mt),
diff --git a/src/rustdoc/attr_pass.rs b/src/rustdoc/attr_pass.rs
index 232b72d369a..71a179e29f0 100644
--- a/src/rustdoc/attr_pass.rs
+++ b/src/rustdoc/attr_pass.rs
@@ -204,14 +204,14 @@ fn merge_method_attrs(
     let attrs: [(str, option<str>)] = astsrv::exec(srv) {|ctxt|
         alt ctxt.ast_map.get(item_id) {
           ast_map::node_item(@{
-            node: ast::item_iface(_, methods), _
+            node: ast::item_iface(_, _, methods), _
           }, _) {
             par::seqmap(methods) {|method|
                 (method.ident, attr_parser::parse_desc(method.attrs))
             }
           }
           ast_map::node_item(@{
-            node: ast::item_impl(_, _, _, methods), _
+            node: ast::item_impl(_, _, _, _, methods), _
           }, _) {
             par::seqmap(methods) {|method|
                 (method.ident, attr_parser::parse_desc(method.attrs))
diff --git a/src/rustdoc/extract.rs b/src/rustdoc/extract.rs
index e9cfdc4db90..fc54a1ea9f6 100644
--- a/src/rustdoc/extract.rs
+++ b/src/rustdoc/extract.rs
@@ -88,12 +88,12 @@ fn moddoc_from_mod(
                     resdoc_from_resource(itemdoc)
                 ))
               }
-              ast::item_iface(_, methods) {
+              ast::item_iface(_, _, methods) {
                 some(doc::ifacetag(
                     ifacedoc_from_iface(itemdoc, methods)
                 ))
               }
-              ast::item_impl(_, _, _, methods) {
+              ast::item_impl(_, _, _, _, methods) {
                 some(doc::impltag(
                     impldoc_from_impl(itemdoc, methods)
                 ))
diff --git a/src/rustdoc/reexport_pass.rs b/src/rustdoc/reexport_pass.rs
index 2b4ed05e3e5..cfb715d2fe4 100644
--- a/src/rustdoc/reexport_pass.rs
+++ b/src/rustdoc/reexport_pass.rs
@@ -292,7 +292,7 @@ fn all_impls(m: ast::_mod) -> map::set<ast::def_id> {
     let all_impls = common::new_def_hash();
     for m.items.each {|item|
         alt item.node {
-          ast::item_impl(_, _, _, _) {
+          ast::item_impl(_, _, _, _, _) {
             all_impls.insert(ast_util::local_def(item.id), ());
           }
           _ { }
diff --git a/src/rustdoc/tystr_pass.rs b/src/rustdoc/tystr_pass.rs
index 58f147ca6ff..56888758ede 100644
--- a/src/rustdoc/tystr_pass.rs
+++ b/src/rustdoc/tystr_pass.rs
@@ -197,7 +197,7 @@ fn get_method_sig(
     astsrv::exec(srv) {|ctxt|
         alt check ctxt.ast_map.get(item_id) {
           ast_map::node_item(@{
-            node: ast::item_iface(_, methods), _
+            node: ast::item_iface(_, _, methods), _
           }, _) {
             alt check vec::find(methods) {|method|
                 method.ident == method_name
@@ -212,7 +212,7 @@ fn get_method_sig(
             }
           }
           ast_map::node_item(@{
-            node: ast::item_impl(_, _, _, methods), _
+            node: ast::item_impl(_, _, _, _, methods), _
           }, _) {
             alt check vec::find(methods) {|method|
                 method.ident == method_name
@@ -247,7 +247,7 @@ fn fold_impl(
     let (iface_ty, self_ty) = astsrv::exec(srv) {|ctxt|
         alt ctxt.ast_map.get(doc.id()) {
           ast_map::node_item(@{
-            node: ast::item_impl(_, iface_ty, self_ty, _), _
+            node: ast::item_impl(_, _, iface_ty, self_ty, _), _
           }, _) {
             let iface_ty = option::map(iface_ty) {|p|
                 pprust::path_to_str(p.path)
diff --git a/src/test/compile-fail/iface-cast.rs b/src/test/compile-fail/iface-cast.rs
new file mode 100644
index 00000000000..5c859f21229
--- /dev/null
+++ b/src/test/compile-fail/iface-cast.rs
@@ -0,0 +1,8 @@
+iface foo<T> { }
+
+fn bar(x: foo<uint>) -> foo<int> {
+    ret (x as foo::<int>);
+    //!^ ERROR mismatched types: expected `foo<int>` but found `foo<uint>`
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/prim-with-args.rs b/src/test/compile-fail/prim-with-args.rs
new file mode 100644
index 00000000000..955d17cb33b
--- /dev/null
+++ b/src/test/compile-fail/prim-with-args.rs
@@ -0,0 +1,29 @@
+fn main() {
+
+let x: int<int>; //! ERROR Type parameters are not allowed on this type.
+let x: i8<int>; //! ERROR Type parameters are not allowed on this type.
+let x: i16<int>; //! ERROR Type parameters are not allowed on this type.
+let x: i32<int>; //! ERROR Type parameters are not allowed on this type.
+let x: i64<int>; //! ERROR Type parameters are not allowed on this type.
+let x: uint<int>; //! ERROR Type parameters are not allowed on this type.
+let x: u8<int>; //! ERROR Type parameters are not allowed on this type.
+let x: u16<int>; //! ERROR Type parameters are not allowed on this type.
+let x: u32<int>; //! ERROR Type parameters are not allowed on this type.
+let x: u64<int>; //! ERROR Type parameters are not allowed on this type.
+let x: float<int>; //! ERROR Type parameters are not allowed on this type.
+let x: char<int>; //! ERROR Type parameters are not allowed on this type.
+
+let x: int/&; //! ERROR Region parameters are not allowed on this type.
+let x: i8/&; //! ERROR Region parameters are not allowed on this type.
+let x: i16/&; //! ERROR Region parameters are not allowed on this type.
+let x: i32/&; //! ERROR Region parameters are not allowed on this type.
+let x: i64/&; //! ERROR Region parameters are not allowed on this type.
+let x: uint/&; //! ERROR Region parameters are not allowed on this type.
+let x: u8/&; //! ERROR Region parameters are not allowed on this type.
+let x: u16/&; //! ERROR Region parameters are not allowed on this type.
+let x: u32/&; //! ERROR Region parameters are not allowed on this type.
+let x: u64/&; //! ERROR Region parameters are not allowed on this type.
+let x: float/&; //! ERROR Region parameters are not allowed on this type.
+let x: char/&; //! ERROR Region parameters are not allowed on this type.
+
+}
diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs
new file mode 100644
index 00000000000..6f9c547d632
--- /dev/null
+++ b/src/test/compile-fail/regions-bounds.rs
@@ -0,0 +1,32 @@
+// Check that explicit region bounds are allowed on the various
+// nominal types (but not on other types) and that they are type
+// checked.
+
+enum an_enum/& { }
+iface an_iface/& { }
+class a_class/& { new() { } }
+resource a_rsrc/&(_x: ()) { }
+
+fn a_fn1(e: an_enum/&a) -> an_enum/&b {
+    ret e; //! ERROR mismatched types: expected `an_enum/&b` but found `an_enum/&a`
+}
+
+fn a_fn2(e: an_iface/&a) -> an_iface/&b {
+    ret e; //! ERROR mismatched types: expected `an_iface/&b` but found `an_iface/&a`
+}
+
+fn a_fn3(e: a_class/&a) -> a_class/&b {
+    ret e; //! ERROR mismatched types: expected `a_class/&b` but found `a_class/&a`
+}
+
+fn a_fn4(e: a_rsrc/&a) -> a_rsrc/&b {
+    ret e; //! ERROR mismatched types: expected `a_rsrc/&b` but found `a_rsrc/&a`
+}
+
+fn a_fn5(e: int/&a) -> int/&b {
+    //!^ ERROR Region parameters are not allowed on this type.
+    //!^^ ERROR Region parameters are not allowed on this type.
+    ret e;
+}
+
+fn main() { }
\ No newline at end of file
diff --git a/src/test/compile-fail/regions-iface-1.rs b/src/test/compile-fail/regions-iface-1.rs
new file mode 100644
index 00000000000..a2a2e39a2f8
--- /dev/null
+++ b/src/test/compile-fail/regions-iface-1.rs
@@ -0,0 +1,28 @@
+type ctxt = { v: uint };
+
+iface get_ctxt/& {
+    // Here the `&` is bound in the method definition:
+    fn get_ctxt() -> &ctxt;
+}
+
+type has_ctxt/& = { c: &ctxt };
+
+impl/& of get_ctxt for has_ctxt {
+
+    // Here an error occurs because we used `&self` but
+    // the definition used `&`:
+    fn get_ctxt() -> &self.ctxt { //! ERROR method `get_ctxt` has an incompatible type
+        self.c
+    }
+
+}
+
+fn get_v(gc: get_ctxt) -> uint {
+    gc.get_ctxt().v
+}
+
+fn main() {
+    let ctxt = { v: 22u };
+    let hc = { c: &ctxt };
+    assert get_v(hc as get_ctxt) == 22u;
+}
diff --git a/src/test/compile-fail/regions-iface-2.rs b/src/test/compile-fail/regions-iface-2.rs
new file mode 100644
index 00000000000..76f4d24291a
--- /dev/null
+++ b/src/test/compile-fail/regions-iface-2.rs
@@ -0,0 +1,21 @@
+type ctxt = { v: uint };
+
+iface get_ctxt/& {
+    fn get_ctxt() -> &self.ctxt;
+}
+
+type has_ctxt/& = { c: &ctxt };
+
+impl/& of get_ctxt for has_ctxt {
+    fn get_ctxt() -> &self.ctxt { self.c }
+}
+
+fn make_gc() -> get_ctxt  {
+    let ctxt = { v: 22u };
+    let hc = { c: &ctxt };
+    ret hc as get_ctxt; //! ERROR mismatched types: expected `get_ctxt/&`
+}
+
+fn main() {
+    make_gc().get_ctxt().v;
+}
diff --git a/src/test/compile-fail/regions-iface-3.rs b/src/test/compile-fail/regions-iface-3.rs
new file mode 100644
index 00000000000..ae8d0130dff
--- /dev/null
+++ b/src/test/compile-fail/regions-iface-3.rs
@@ -0,0 +1,14 @@
+iface get_ctxt/& {
+    fn get_ctxt() -> &self.uint;
+}
+
+fn make_gc1(gc: get_ctxt/&a) -> get_ctxt/&b  {
+    ret gc; //! ERROR mismatched types: expected `get_ctxt/&b` but found `get_ctxt/&a`
+}
+
+fn make_gc2(gc: get_ctxt/&a) -> get_ctxt/&b  {
+    ret gc as get_ctxt; //! ERROR mismatched types: expected `get_ctxt/&b` but found `get_ctxt/&a`
+}
+
+fn main() {
+}
diff --git a/src/test/run-pass/regions-borrow-evec-at.rs b/src/test/run-pass/regions-borrow-evec-at.rs
index 577cc980b00..e061f566e12 100644
--- a/src/test/run-pass/regions-borrow-evec-at.rs
+++ b/src/test/run-pass/regions-borrow-evec-at.rs
@@ -1,4 +1,4 @@
-// xfail-test it don't work yet
+// xfail-test
 
 fn foo(x: [uint]/&) -> uint {
     x[0]
diff --git a/src/test/run-pass/regions-borrow-evec-fixed.rs b/src/test/run-pass/regions-borrow-evec-fixed.rs
index 906333aa207..50306b57139 100644
--- a/src/test/run-pass/regions-borrow-evec-fixed.rs
+++ b/src/test/run-pass/regions-borrow-evec-fixed.rs
@@ -1,4 +1,5 @@
 // xfail-test
+
 fn foo(x: [int]/&) -> int {
     x[0]
 }
diff --git a/src/test/run-pass/regions-iface.rs b/src/test/run-pass/regions-iface.rs
new file mode 100644
index 00000000000..6bc8f172f98
--- /dev/null
+++ b/src/test/run-pass/regions-iface.rs
@@ -0,0 +1,23 @@
+type ctxt = { v: uint };
+
+iface get_ctxt/& {
+    fn get_ctxt() -> &self.ctxt;
+}
+
+type has_ctxt/& = { c: &ctxt };
+
+impl/& of get_ctxt for has_ctxt {
+    fn get_ctxt() -> &self.ctxt {
+        self.c
+    }
+}
+
+fn get_v(gc: get_ctxt) -> uint {
+    gc.get_ctxt().v
+}
+
+fn main() {
+    let ctxt = { v: 22u };
+    let hc = { c: &ctxt };
+    assert get_v(hc as get_ctxt) == 22u;
+}
diff --git a/src/test/run-pass/regions-self-impls.rs b/src/test/run-pass/regions-self-impls.rs
index a587c19f38f..e29d88cc78d 100644
--- a/src/test/run-pass/regions-self-impls.rs
+++ b/src/test/run-pass/regions-self-impls.rs
@@ -1,9 +1,6 @@
-// xfail-test
-// ^ handling of self is currently broken
+type clam/& = { chowder: &int };
 
-type clam = { chowder: &int };
-
-impl clam for clam {
+impl clam/& for clam {
     fn get_chowder() -> &self.int { ret self.chowder; }
 }
 
diff --git a/src/test/run-pass/regions-self-in-enums.rs b/src/test/run-pass/regions-self-in-enums.rs
index 084192c3aa7..ced26c8c7db 100644
--- a/src/test/run-pass/regions-self-in-enums.rs
+++ b/src/test/run-pass/regions-self-in-enums.rs
@@ -1,6 +1,4 @@
-// xfail-test
-
-enum int_wrapper {
+enum int_wrapper/& {
     int_wrapper_ctor(&int)
 }