about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-03-23 11:37:10 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-03-23 12:22:58 -0700
commit7931a61ebb689723526bf14857ff06b6b7db2cfd (patch)
tree3a1f7352ea511800a15e26e4b0436117d11c31e1 /src/rustc
parent84019aa0dcf8990a770764e99621568a39aeabd3 (diff)
downloadrust-7931a61ebb689723526bf14857ff06b6b7db2cfd.tar.gz
rust-7931a61ebb689723526bf14857ff06b6b7db2cfd.zip
rustc: Redo region inference to be a bit less broken
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/metadata/tyencode.rs20
-rw-r--r--src/rustc/middle/region.rs97
-rw-r--r--src/rustc/middle/regionck.rs4
-rw-r--r--src/rustc/middle/resolve.rs1
-rw-r--r--src/rustc/middle/ty.rs316
-rw-r--r--src/rustc/middle/typeck.rs263
-rw-r--r--src/rustc/util/ppaux.rs18
7 files changed, 390 insertions, 329 deletions
diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs
index c526777f37e..80f830ce88d 100644
--- a/src/rustc/metadata/tyencode.rs
+++ b/src/rustc/metadata/tyencode.rs
@@ -92,23 +92,23 @@ fn enc_mt(w: io::writer, cx: @ctxt, mt: ty::mt) {
     }
     enc_ty(w, cx, mt.ty);
 }
-fn enc_region(w: io::writer, cx: @ctxt, r: ty::region) {
+fn enc_region(w: io::writer, r: ty::region) {
     alt r {
-        ty::re_named(did) {
-            w.write_char('n'); w.write_str(cx.ds(did)); w.write_char('|');
-        }
-        ty::re_caller(did) {
-            w.write_char('c'); w.write_str(cx.ds(did)); w.write_char('|');
-        }
         ty::re_block(nid) {
             w.write_char('b'); w.write_int(nid); w.write_char('|');
         }
-        ty::re_self(did) {
-            w.write_char('s'); w.write_str(cx.ds(did)); w.write_char('|');
+        ty::re_self {
+            w.write_char('s');
+        }
+        ty::re_inferred {
+            w.write_char('i');
         }
         ty::re_param(id) {
             w.write_char('p'); w.write_uint(id); w.write_char('|');
         }
+        ty::re_var(id) {
+            w.write_char('v'); w.write_uint(id); w.write_char('|');
+        }
     }
 }
 fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
@@ -167,7 +167,7 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
       ty::ty_ptr(mt) { w.write_char('*'); enc_mt(w, cx, mt); }
       ty::ty_rptr(r, mt) {
         w.write_char('&');
-        enc_region(w, cx, r);
+        enc_region(w, r);
         enc_mt(w, cx, mt);
       }
       ty::ty_vec(mt) { w.write_char('I'); enc_mt(w, cx, mt); }
diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs
index a6806b642e8..3998c2525ac 100644
--- a/src/rustc/middle/region.rs
+++ b/src/rustc/middle/region.rs
@@ -22,10 +22,10 @@ enum parent {
     pa_crate
 }
 
-/* Records the binding site of a region name. */
+/* Records the parameter ID of a region name. */
 type binding = {
     name: str,
-    id: ast::def_id
+    id: uint
 };
 
 type region_map = {
@@ -35,12 +35,8 @@ type region_map = {
     ast_type_to_region: hashmap<ast::node_id,ty::region>,
     /* Mapping from a local variable to its containing block. */
     local_blocks: hashmap<ast::node_id,ast::node_id>,
-    /* Mapping from a region name to its function. */
-    region_name_to_fn: hashmap<ast::def_id,ast::node_id>,
     /* Mapping from an AST type node to the region that `&` resolves to. */
     ast_type_to_inferred_region: hashmap<ast::node_id,ty::region>,
-    /* Mapping from a call site (or `bind` site) to its containing block. */
-    call_site_to_block: hashmap<ast::node_id,ast::node_id>,
     /*
      * Mapping from an address-of operator or alt expression to its containing
      * block. This is used as the region if the operand is an rvalue.
@@ -67,22 +63,12 @@ type ctxt = {
     /* True if we're within the pattern part of an alt, false otherwise. */
     in_alt: bool,
 
-    /*
-     * Points to the site of the current typeclass implementation, or none if
-     * we're outside one.
-     */
-    self_binding: option<ast::def_id>
-};
+    /* True if we're within a typeclass implementation, false otherwise. */
+    in_typeclass: bool,
 
-fn region_to_scope(region_map: @region_map, region: ty::region)
-        -> ast::node_id {
-    ret alt region {
-        ty::re_caller(def_id) | ty::re_self(def_id) { def_id.node }
-        ty::re_named(def_id) { region_map.region_name_to_fn.get(def_id) }
-        ty::re_block(node_id) { node_id }
-        ty::re_param(_) { fail "unresolved region in region_to_scope" }
-    };
-}
+    /* The next parameter ID. */
+    mut next_param_id: uint
+};
 
 // Returns true if `subscope` is equal to or is lexically nested inside
 // `superscope` and false otherwise.
@@ -105,8 +91,10 @@ fn get_inferred_region(cx: ctxt, sp: syntax::codemap::span) -> ty::region {
     // TODO: What do we do if we're in an alt?
 
     ret alt cx.parent {
-        pa_fn_item(item_id) | pa_nested_fn(item_id) {
-            ty::re_caller({crate: ast::local_crate, node: item_id})
+        pa_fn_item(_) | pa_nested_fn(_) {
+            let id = cx.next_param_id;
+            cx.next_param_id += 1u;
+            ty::re_param(id)
         }
         pa_block(block_id) { ty::re_block(block_id) }
         pa_item(_) { ty::re_param(0u) }
@@ -123,17 +111,14 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
             alt node {
                 ast::re_inferred { /* no-op */ }
                 ast::re_self {
-                    alt cx.self_binding {
-                        some(def_id) {
-                            let region = ty::re_self(def_id);
-                            let rm = cx.region_map;
-                            rm.ast_type_to_region.insert(region_id, region);
-                        }
-                        none {
-                            cx.sess.span_err(ty.span,
-                                             "the `self` region is not \
-                                              allowed here");
-                        }
+                    if cx.in_typeclass {
+                        let r = ty::re_self;
+                        let rm = cx.region_map;
+                        rm.ast_type_to_region.insert(region_id, r);
+                    } else {
+                        cx.sess.span_err(ty.span,
+                                         "the `self` region is not allowed \
+                                          here");
                     }
                 }
                 ast::re_named(ident) {
@@ -142,18 +127,18 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
                     let bindings = cx.bindings;
                     let mut region;
                     alt list::find(*bindings, {|b| ident == b.name}) {
-                        some(binding) { region = ty::re_named(binding.id); }
+                        some(binding) { region = ty::re_param(binding.id); }
                         none {
-                            let def_id = {crate: ast::local_crate,
-                                          node: region_id};
-                            let binding = {name: ident, id: def_id};
+                            let id = cx.next_param_id;
+                            let binding = {name: ident, id: id};
+                            cx.next_param_id += 1u;
+
                             cx.bindings = @list::cons(binding, cx.bindings);
-                            region = ty::re_named(def_id);
+                            region = ty::re_param(id);
 
                             alt cx.parent {
                                 pa_fn_item(fn_id) | pa_nested_fn(fn_id) {
-                                    let rf = cx.region_map.region_name_to_fn;
-                                    rf.insert(def_id, fn_id);
+                                    /* ok */
                                 }
                                 pa_item(_) {
                                     cx.sess.span_err(ty.span,
@@ -264,16 +249,6 @@ fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
                           in_alt: false with cx};
             visit::visit_expr(expr, new_cx, visitor);
         }
-        ast::expr_call(_, _, _) | ast::expr_bind(_, _) {
-            // Record the block that this call appears in.
-            alt cx.parent {
-                pa_block(blk_id) {
-                    cx.region_map.call_site_to_block.insert(expr.id, blk_id);
-                }
-                _ { cx.sess.span_bug(expr.span, "expr outside of block?!"); }
-            }
-            visit::visit_expr(expr, cx, visitor);
-        }
         ast::expr_addr_of(_, subexpr) | ast::expr_alt(subexpr, _, _) {
             // Record the block that this expression appears in, in case the
             // operand is an rvalue.
@@ -302,22 +277,29 @@ fn resolve_local(local: @ast::local, cx: ctxt, visitor: visit::vt<ctxt>) {
 fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt<ctxt>) {
     // Items create a new outer block scope as far as we're concerned.
     let mut parent;
-    let mut self_binding = cx.self_binding;
+    let mut in_typeclass;
     alt item.node {
         ast::item_fn(_, _, _) | ast::item_enum(_, _) {
             parent = pa_fn_item(item.id);
+            in_typeclass = false;
         }
         ast::item_impl(_, _, _, _) {
-            self_binding = some({crate: ast::local_crate, node: item.id});
             parent = pa_item(item.id);
+            in_typeclass = true;
+        }
+        _ {
+            parent = pa_item(item.id);
+            in_typeclass = false;
         }
-        _ { parent = pa_item(item.id); }
     };
+
     let new_cx: ctxt = {bindings: @list::nil,
                         parent: parent,
                         in_alt: false,
-                        self_binding: self_binding
+                        in_typeclass: in_typeclass,
+                        mut next_param_id: 0u
                         with cx};
+
     visit::visit_item(item, new_cx, visitor);
 }
 
@@ -328,16 +310,15 @@ fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
                     region_map: @{parents: map::int_hash(),
                                   ast_type_to_region: map::int_hash(),
                                   local_blocks: map::int_hash(),
-                                  region_name_to_fn: new_def_hash(),
                                   ast_type_to_inferred_region:
                                     map::int_hash(),
-                                  call_site_to_block: map::int_hash(),
                                   rvalue_to_block: map::int_hash()},
                     mut bindings: @list::nil,
                     mut queued_locals: [],
                     parent: pa_crate,
                     in_alt: false,
-                    self_binding: none};
+                    in_typeclass: false,
+                    mut next_param_id: 0u};
     let visitor = visit::mk_vt(@{
         visit_block: resolve_block,
         visit_item: resolve_item,
diff --git a/src/rustc/middle/regionck.rs b/src/rustc/middle/regionck.rs
index 26316422106..a969785cd2e 100644
--- a/src/rustc/middle/regionck.rs
+++ b/src/rustc/middle/regionck.rs
@@ -28,7 +28,7 @@ fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
             alt ty::get(t).struct {
                 ty::ty_rptr(region, _) {
                     alt region {
-                        ty::re_named(_) | ty::re_caller(_) | ty::re_self(_) {
+                        ty::re_self | ty::re_inferred | ty::re_param(_) {
                             /* ok */
                         }
                         ty::re_block(rbi) {
@@ -51,7 +51,7 @@ fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
                                                      "escapes its block");
                             }
                         }
-                        ty::re_param(_) {
+                        ty::re_var(_) {
                             cx.tcx.sess.span_bug(expr.span,
                                                  "unresolved region");
                         }
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index ad5243a01a9..5a4c1ae1d7a 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -2004,6 +2004,7 @@ fn check_exports(e: @env) {
                         maybe_add_reexport(e, export_id, t);
                         maybe_add_reexport(e, export_id, m);
                       }
+                      _ { e.sess.span_bug(vi.span, "unresolved export"); }
                     }
                   }
                   mie_item(@{id, _}) | mie_native_item(@{id, _}) |
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 38d2ba369ec..b3f6a565c75 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -91,7 +91,7 @@ export ty_uint, mk_uint, mk_mach_uint;
 export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box;
 export ty_var, mk_var;
 export ty_self, mk_self;
-export region, re_named, re_caller, re_block, re_param;
+export region, re_block, re_param, re_var;
 export get, type_has_params, type_has_vars, type_has_rptrs, type_id;
 export same_type;
 export ty_var_id;
@@ -139,7 +139,7 @@ export default_arg_mode_for_ty;
 export item_path;
 export item_path_str;
 export ast_ty_to_ty_cache_entry;
-export atttce_unresolved, atttce_resolved, atttce_has_regions;
+export atttce_unresolved, atttce_resolved;
 
 // Data types
 
@@ -174,8 +174,7 @@ type intern_key = {struct: sty, o_def_id: option<ast::def_id>};
 
 enum ast_ty_to_ty_cache_entry {
     atttce_unresolved,  /* not resolved yet */
-    atttce_resolved(t), /* resolved to a type, irrespective of region */
-    atttce_has_regions  /* has regions; cannot be cached */
+    atttce_resolved(t)  /* resolved to a type, irrespective of region */
 }
 
 type ctxt =
@@ -240,14 +239,19 @@ type fn_ty = {proto: ast::proto,
               constraints: [@constr]};
 
 enum region {
-    re_named(def_id),
-    re_caller(def_id),
-    re_self(def_id),
+    // The region of a block.
     re_block(node_id),
+    // The self region. Only valid inside classes and typeclass
+    // implementations.
+    re_self,
+    // The inferred region, which also corresponds to &self in typedefs.
+    re_inferred,
 
-    // A region parameter. Currently used only for typedefs.
-    // TODO: Use this for caller and named regions as well.
-    re_param(uint)
+    // A region parameter.
+    re_param(uint),
+
+    // A region variable.
+    re_var(uint)
 }
 
 // NB: If you change this, you'll probably want to change the corresponding
@@ -594,100 +598,123 @@ fn maybe_walk_ty(ty: t, f: fn(t) -> bool) {
 enum fold_mode {
     fm_var(fn@(int) -> t),
     fm_param(fn@(uint, def_id) -> t),
-    fm_rptr(fn@(region) -> region),
+    fm_rptr(fn@(region, bool /* under & */) -> region),
     fm_general(fn@(t) -> t),
 }
 
 fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
-    let mut ty = ty_0;
-
-    let tb = get(ty);
-    alt fld {
-      fm_var(_) { if !tb.has_vars { ret ty; } }
-      fm_param(_) { if !tb.has_params { ret ty; } }
-      fm_rptr(_) { if !tb.has_rptrs { ret ty; } }
-      fm_general(_) {/* no fast path */ }
-    }
+    fn do_fold(cx: ctxt, fld: fold_mode, ty_0: t, under_rptr: bool) -> t {
+        let mut ty = ty_0;
+
+        let tb = get(ty);
+        alt fld {
+          fm_var(_) { if !tb.has_vars { ret ty; } }
+          fm_param(_) { if !tb.has_params { ret ty; } }
+          fm_rptr(_) { if !tb.has_rptrs { ret ty; } }
+          fm_general(_) {/* no fast path */ }
+        }
 
-    alt tb.struct {
-      ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
-      ty_str | ty_type | ty_opaque_closure_ptr(_) |
-      ty_opaque_box {}
-      ty_box(tm) {
-        ty = mk_box(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl});
-      }
-      ty_uniq(tm) {
-        ty = mk_uniq(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl});
-      }
-      ty_ptr(tm) {
-        ty = mk_ptr(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl});
-      }
-      ty_vec(tm) {
-        ty = mk_vec(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl});
-      }
-      ty_enum(tid, subtys) {
-        ty = mk_enum(cx, tid, vec::map(subtys, {|t| fold_ty(cx, fld, t) }));
-      }
-      ty_iface(did, subtys) {
-        ty = mk_iface(cx, did, vec::map(subtys, {|t| fold_ty(cx, fld, t) }));
-      }
-      ty_self(subtys) {
-        ty = mk_self(cx, vec::map(subtys, {|t| fold_ty(cx, fld, t) }));
-      }
-      ty_rec(fields) {
-        let mut new_fields: [field] = [];
-        for fl: field in fields {
-            let new_ty = fold_ty(cx, fld, fl.mt.ty);
-            let new_mt = {ty: new_ty, mutbl: fl.mt.mutbl};
-            new_fields += [{ident: fl.ident, mt: new_mt}];
+        alt tb.struct {
+          ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
+          ty_str | ty_type | ty_opaque_closure_ptr(_) |
+          ty_opaque_box {}
+          ty_box(tm) {
+            ty = mk_box(cx, {ty: do_fold(cx, fld, tm.ty, under_rptr),
+                             mutbl: tm.mutbl});
+          }
+          ty_uniq(tm) {
+            ty = mk_uniq(cx, {ty: do_fold(cx, fld, tm.ty, under_rptr),
+                              mutbl: tm.mutbl});
+          }
+          ty_ptr(tm) {
+            ty = mk_ptr(cx, {ty: do_fold(cx, fld, tm.ty, under_rptr),
+                             mutbl: tm.mutbl});
+          }
+          ty_vec(tm) {
+            ty = mk_vec(cx, {ty: do_fold(cx, fld, tm.ty, under_rptr),
+                             mutbl: tm.mutbl});
+          }
+          ty_enum(tid, subtys) {
+            ty = mk_enum(cx, tid,
+                         vec::map(subtys, {|t|
+                            do_fold(cx, fld, t, under_rptr)
+                         }));
+          }
+          ty_iface(did, subtys) {
+            ty = mk_iface(cx, did,
+                          vec::map(subtys, {|t|
+                              do_fold(cx, fld, t, under_rptr)
+                          }));
+          }
+          ty_self(subtys) {
+            ty = mk_self(cx, vec::map(subtys, {|t|
+                                do_fold(cx, fld, t, under_rptr)
+                             }));
+          }
+          ty_rec(fields) {
+            let mut new_fields: [field] = [];
+            for fl: field in fields {
+                let new_ty = do_fold(cx, fld, fl.mt.ty, under_rptr);
+                let new_mt = {ty: new_ty, mutbl: fl.mt.mutbl};
+                new_fields += [{ident: fl.ident, mt: new_mt}];
+            }
+            ty = mk_rec(cx, new_fields);
+          }
+          ty_tup(ts) {
+            let mut new_ts = [];
+            for tt in ts { new_ts += [do_fold(cx, fld, tt, under_rptr)]; }
+            ty = mk_tup(cx, new_ts);
+          }
+          ty_fn(f) {
+            let mut new_args: [arg] = [];
+            for a: arg in f.inputs {
+                let new_ty = do_fold(cx, fld, a.ty, under_rptr);
+                new_args += [{mode: a.mode, ty: new_ty}];
+            }
+            ty = mk_fn(cx, {inputs: new_args,
+                            output: do_fold(cx, fld, f.output, under_rptr)
+                            with f});
+          }
+          ty_res(did, subty, tps) {
+            let mut new_tps = [];
+            for tp: t in tps {
+                new_tps += [do_fold(cx, fld, tp, under_rptr)];
+            }
+            ty = mk_res(cx, did, do_fold(cx, fld, subty, under_rptr),
+                        new_tps);
+          }
+          ty_var(id) {
+            alt fld { fm_var(folder) { ty = folder(id); } _ {/* no-op */ } }
+          }
+          ty_param(id, did) {
+            alt fld { fm_param(folder) { ty = folder(id, did); } _ {} }
+          }
+          ty_rptr(r, tm) {
+            let region = alt fld {
+                fm_rptr(folder) { folder(r, under_rptr) }
+                _ { r }
+            };
+            ty = mk_rptr(cx, region,
+                         {ty: do_fold(cx, fld, tm.ty, true),
+                          mutbl: tm.mutbl});
+          }
+          ty_constr(subty, cs) {
+              ty = mk_constr(cx, do_fold(cx, fld, subty, under_rptr), cs);
+          }
+          _ {
+              cx.sess.bug("unsupported sort of type in fold_ty");
+          }
         }
-        ty = mk_rec(cx, new_fields);
-      }
-      ty_tup(ts) {
-        let mut new_ts = [];
-        for tt in ts { new_ts += [fold_ty(cx, fld, tt)]; }
-        ty = mk_tup(cx, new_ts);
-      }
-      ty_fn(f) {
-        let mut new_args: [arg] = [];
-        for a: arg in f.inputs {
-            let new_ty = fold_ty(cx, fld, a.ty);
-            new_args += [{mode: a.mode, ty: new_ty}];
+        alt tb.o_def_id {
+          some(did) { ty = mk_t_with_id(cx, get(ty).struct, some(did)); }
+          _ {}
         }
-        ty = mk_fn(cx, {inputs: new_args,
-                        output: fold_ty(cx, fld, f.output)
-                        with f});
-      }
-      ty_res(did, subty, tps) {
-        let mut new_tps = [];
-        for tp: t in tps { new_tps += [fold_ty(cx, fld, tp)]; }
-        ty = mk_res(cx, did, fold_ty(cx, fld, subty), new_tps);
-      }
-      ty_var(id) {
-        alt fld { fm_var(folder) { ty = folder(id); } _ {/* no-op */ } }
-      }
-      ty_param(id, did) {
-        alt fld { fm_param(folder) { ty = folder(id, did); } _ {} }
-      }
-      ty_rptr(r, tm) {
-        let region = alt fld { fm_rptr(folder) { folder(r) } _ { r } };
-        ty = mk_rptr(cx, region,
-                     {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl});
-      }
-      ty_constr(subty, cs) {
-          ty = mk_constr(cx, fold_ty(cx, fld, subty), cs);
-      }
-      _ {
-          cx.sess.bug("unsupported sort of type in fold_ty");
-      }
-    }
-    alt tb.o_def_id {
-      some(did) { ty = mk_t_with_id(cx, get(ty).struct, some(did)); }
-      _ {}
+
+        // If this is a general type fold, then we need to run it now.
+        alt fld { fm_general(folder) { ret folder(ty); } _ { ret ty; } }
     }
 
-    // If this is a general type fold, then we need to run it now.
-    alt fld { fm_general(folder) { ret folder(ty); } _ { ret ty; } }
+    ret do_fold(cx, fld, ty_0, false);
 }
 
 
@@ -1168,11 +1195,11 @@ fn hash_type_structure(st: sty) -> uint {
     }
     fn hash_region(r: region) -> uint {
         alt r {
-          re_named(_)   { 1u }
-          re_caller(_)  { 2u }
-          re_self(_)    { 3u }
-          re_block(_)   { 4u }
-          re_param(_)   { 5u }
+          re_block(_)   { 0u }
+          re_self       { 1u }
+          re_inferred   { 2u }
+          re_param(_)   { 3u }
+          re_var(_)     { 4u }
         }
     }
     alt st {
@@ -1643,7 +1670,7 @@ mod unify {
             fn@(rb: @region_bindings, r: region) {
                 ufind::union(rb.sets, set_a, set_b);
                 let root_c: uint = ufind::find(rb.sets, set_a);
-                smallintmap::insert::<region>(rb.regions, root_c, r);
+                smallintmap::insert(rb.regions, root_c, r);
             }
         );
 
@@ -2013,39 +2040,69 @@ mod unify {
         cx: @uctxt, e_region: region, a_region: region,
         variance: variance,
         nxt: fn(region) -> ures<T>) -> ures<T> {
-        let {sub, super} = alt variance {
-          covariant { {sub: a_region, super: e_region} }
-          contravariant { {sub: e_region, super: a_region} }
-          invariant {
-            ret if e_region == a_region {
-                  nxt(e_region)
-              } else {
-                  err(terr_regions_differ(true, e_region, a_region))
-              };
-            }
-        };
+        let mut sub, super;
+        alt variance {
+            covariant | invariant { super = e_region; sub = a_region; }
+            contravariant { super = a_region; sub = e_region; }
+        }
 
-        // FIXME: This is wrong. We should be keeping a set of region bindings
-        // around.
-        alt (sub, super) {
-            (ty::re_param(_), _) | (_, ty::re_param(_)) {
-                ret if sub == super {
-                    nxt(super)
-                } else {
-                    err(terr_regions_differ(true, super, sub))
-                }
+        // FIXME: Should have a way of unifying regions that relies on bounds,
+        // not on unification.
+        alt (super, sub) {
+            (ty::re_var(superkey), ty::re_var(subkey)) {
+                ret union_region_sets(cx, subkey, superkey, variance,
+                                      {|| nxt(sub) });
+            }
+            (ty::re_var(superkey), _) {
+                ret record_region_binding(cx, superkey, sub, variance, nxt);
+            }
+            (_, ty::re_var(subkey)) {
+                ret record_region_binding(cx, subkey, super, variance, nxt);
             }
             _ { /* fall through */ }
         }
 
-        // Outer regions are subtypes of inner regions. (This is somewhat
-        // surprising!)
-        let superscope = region::region_to_scope(cx.tcx.region_map, super);
-        let subscope = region::region_to_scope(cx.tcx.region_map, sub);
-        if region::scope_contains(cx.tcx.region_map, subscope, superscope) {
-            ret nxt(super);
+        if variance == invariant {
+          ret if e_region == a_region {
+              nxt(e_region)
+          } else {
+              err(terr_regions_differ(true, e_region, a_region))
+          };
+        }
+
+        alt (super, sub) {
+            (ty::re_var(_), _) | (_, ty::re_var(_)) {
+                fail "should have been handled above";
+            }
+            (ty::re_inferred, _) | (_, ty::re_inferred) {
+                fail "tried to unify inferred regions";
+            }
+            (ty::re_param(_), ty::re_param(_)) |
+            (ty::re_self, ty::re_self) {
+                ret if super == sub {
+                    nxt(ty::re_self)
+                } else {
+                    err(terr_regions_differ(false, super, sub))
+                };
+            }
+            (ty::re_param(_), ty::re_block(_)) |
+            (ty::re_self, ty::re_block(_)) {
+                ret nxt(super);
+            }
+            (ty::re_block(_), ty::re_param(_)) |
+            (ty::re_block(_), ty::re_self) {
+                ret err(terr_regions_differ(false, super, sub));
+            }
+            (ty::re_block(superblock), ty::re_block(subblock)) {
+                // Outer regions are subtypes of inner regions. (This is
+                // somewhat surprising!)
+                let rm = cx.tcx.region_map;
+                if region::scope_contains(rm, subblock, superblock) {
+                    ret nxt(super);
+                }
+                ret err(terr_regions_differ(false, sub, super));
+            }
         }
-        ret err(terr_regions_differ(false, sub, super));
     }
 
     fn unify_field<T:copy>(
@@ -2074,6 +2131,9 @@ mod unify {
         // Fast path.
         if expected == actual { ret nxt(expected); }
 
+        // FIXME: This is terribly wrong. We should be unifying type sets
+        // using some sort of bound.
+
         alt (get(expected).struct, get(actual).struct) {
           (ty_var(e_id), ty_var(a_id)) {
             union(cx, e_id as uint, a_id as uint, variance) {||
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 6e0b39373a1..19c3e273949 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -253,21 +253,10 @@ enum mode { m_collect, m_check, m_check_tyvar(@fn_ctxt), }
 // internal notion of a type. `getter` is a function that returns the type
 // corresponding to a definition ID:
 fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
-    fn subst_inferred_regions(tcx: ty::ctxt, use_site: ast::node_id,
-                              ty: ty::t) -> ty::t {
-        ret ty::fold_ty(tcx, ty::fm_rptr({|r|
-            alt r {
-                // FIXME: This is probably wrong for params.
-                ty::re_param(_) | ty::re_self(_) {
-                    tcx.region_map.ast_type_to_inferred_region.get(use_site)
-                }
-                _ { r }
-            }
-        }), ty);
-    }
-    fn getter(tcx: ty::ctxt, use_site: ast::node_id, mode: mode,
-              id: ast::def_id) -> ty::ty_param_bounds_and_ty {
-        let tpt = alt mode {
+    fn getter(tcx: ty::ctxt, mode: mode, id: ast::def_id)
+            -> ty::ty_param_bounds_and_ty {
+
+        alt mode {
           m_check | m_check_tyvar(_) { ty::lookup_item_type(tcx, id) }
           m_collect {
             if id.crate != ast::local_crate { csearch::get_type(tcx, id) }
@@ -285,23 +274,14 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
                 }
             }
           }
-        };
-
-        if ty::type_has_rptrs(tpt.ty) {
-            ret {bounds: tpt.bounds,
-                 ty: subst_inferred_regions(tcx, use_site, tpt.ty)};
         }
-        ret tpt;
     }
-    fn ast_mt_to_mt(tcx: ty::ctxt, use_site: ast::node_id, mode: mode,
-                    mt: ast::mt) -> ty::mt {
-        ret {ty: do_ast_ty_to_ty(tcx, use_site, mode, mt.ty),
-             mutbl: mt.mutbl};
+    fn ast_mt_to_mt(tcx: ty::ctxt, mode: mode, mt: ast::mt) -> ty::mt {
+        ret {ty: do_ast_ty_to_ty(tcx, mode, mt.ty), mutbl: mt.mutbl};
     }
-    fn instantiate(tcx: ty::ctxt, use_site: ast::node_id, sp: span,
-                   mode: mode, id: ast::def_id, path_id: ast::node_id,
-                   args: [@ast::ty]) -> ty::t {
-        let ty_param_bounds_and_ty = getter(tcx, use_site, mode, id);
+    fn instantiate(tcx: ty::ctxt, sp: span, mode: mode, id: ast::def_id,
+                   path_id: ast::node_id, args: [@ast::ty]) -> ty::t {
+        let ty_param_bounds_and_ty = getter(tcx, mode, id);
         if vec::len(*ty_param_bounds_and_ty.bounds) == 0u {
             ret ty_param_bounds_and_ty.ty;
         }
@@ -313,7 +293,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
                                      polymorphic type");
         }
         for ast_ty: @ast::ty in args {
-            param_bindings += [do_ast_ty_to_ty(tcx, use_site, mode, ast_ty)];
+            param_bindings += [do_ast_ty_to_ty(tcx, mode, ast_ty)];
         }
         #debug("substituting(%s into %s)",
                str::concat(vec::map(param_bindings, {|t| ty_to_str(tcx, t)})),
@@ -324,8 +304,9 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
         write_substs(tcx, path_id, param_bindings);
         ret typ;
     }
-    fn do_ast_ty_to_ty(tcx: ty::ctxt, use_site: ast::node_id, mode: mode,
-                       &&ast_ty: @ast::ty) -> ty::t {
+    fn do_ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty)
+            -> ty::t {
+
         alt tcx.ast_ty_to_ty_cache.find(ast_ty) {
           some(ty::atttce_resolved(ty)) { ret ty; }
           some(ty::atttce_unresolved) {
@@ -333,7 +314,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
                                               insert a enum in the cycle, \
                                               if this is desired)");
           }
-          some(ty::atttce_has_regions) | none { /* go on */ }
+          none { /* go on */ }
         }
 
         tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_unresolved);
@@ -341,46 +322,37 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
           ast::ty_nil { ty::mk_nil(tcx) }
           ast::ty_bot { ty::mk_bot(tcx) }
           ast::ty_box(mt) {
-            ty::mk_box(tcx, ast_mt_to_mt(tcx, use_site, mode, mt))
+            ty::mk_box(tcx, ast_mt_to_mt(tcx, mode, mt))
           }
           ast::ty_uniq(mt) {
-            ty::mk_uniq(tcx, ast_mt_to_mt(tcx, use_site, mode, mt))
+            ty::mk_uniq(tcx, ast_mt_to_mt(tcx, mode, mt))
           }
           ast::ty_vec(mt) {
-            ty::mk_vec(tcx, ast_mt_to_mt(tcx, use_site, mode, mt))
+            ty::mk_vec(tcx, ast_mt_to_mt(tcx, mode, mt))
           }
           ast::ty_ptr(mt) {
-            ty::mk_ptr(tcx, ast_mt_to_mt(tcx, use_site, mode, mt))
+            ty::mk_ptr(tcx, ast_mt_to_mt(tcx, mode, mt))
           }
           ast::ty_rptr(region, mt) {
             let region = alt region.node {
-                ast::re_inferred {
-                    let attir = tcx.region_map.ast_type_to_inferred_region;
-                    alt attir.find(ast_ty.id) {
-                        some(resolved_region) { resolved_region }
-                        none {
-                            // FIXME: Shouldn't be 0u and should instead be
-                            // a fresh variable.
-                            ty::re_param(0u)
-                        }
-                    }
-                }
-                ast::re_named(_) | ast::re_self {
+                ast::re_inferred { ty::re_inferred }
+                ast::re_self { ty::re_self }
+                ast::re_named(_) {
                     tcx.region_map.ast_type_to_region.get(region.id)
                 }
             };
-            ty::mk_rptr(tcx, region, ast_mt_to_mt(tcx, use_site, mode, mt))
+            ty::mk_rptr(tcx, region, ast_mt_to_mt(tcx, mode, mt))
           }
           ast::ty_tup(fields) {
-            let flds = vec::map(fields,
-                                bind do_ast_ty_to_ty(tcx, use_site, mode, _));
+            let flds = vec::map(fields, bind do_ast_ty_to_ty(tcx, mode, _));
             ty::mk_tup(tcx, flds)
           }
           ast::ty_rec(fields) {
-            let flds = vec::map(fields) {|f|
-                let tm = ast_mt_to_mt(tcx, use_site, mode, f.node.mt);
-                {ident: f.node.ident, mt: tm}
-            };
+            let mut flds: [field] = [];
+            for f: ast::ty_field in fields {
+                let tm = ast_mt_to_mt(tcx, mode, f.node.mt);
+                flds += [{ident: f.node.ident, mt: tm}];
+            }
             ty::mk_rec(tcx, flds)
           }
           ast::ty_fn(proto, decl) {
@@ -393,7 +365,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
               some(d) { d }};
             alt a_def {
               ast::def_ty(did) {
-                instantiate(tcx, use_site, ast_ty.span, mode, did,
+                instantiate(tcx, ast_ty.span, mode, did,
                             id, path.node.types)
               }
               ast::def_prim_ty(nty) {
@@ -421,7 +393,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
                                                         self type");
                     }
                     ty::mk_self(tcx, vec::map(path.node.types, {|ast_ty|
-                        do_ast_ty_to_ty(tcx, use_site, mode, ast_ty)
+                        do_ast_ty_to_ty(tcx, mode, ast_ty)
                     }))
                   }
                 }
@@ -445,7 +417,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
                 }
               }
               else {
-                  getter(tcx, use_site, mode, class_id).ty
+                  getter(tcx, mode, class_id).ty
               }
              }
              _ {
@@ -455,11 +427,11 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
             }
           }
           ast::ty_constr(t, cs) {
-            let out_cs = vec::map(cs) {|constr|
-                ty::ast_constr_to_constr(tcx, constr)
-            };
-            ty::mk_constr(tcx, do_ast_ty_to_ty(tcx, use_site, mode, t),
-                          out_cs)
+            let mut out_cs = [];
+            for constr: @ast::ty_constr in cs {
+                out_cs += [ty::ast_constr_to_constr(tcx, constr)];
+            }
+            ty::mk_constr(tcx, do_ast_ty_to_ty(tcx, mode, t), out_cs)
           }
           ast::ty_infer {
             alt mode {
@@ -474,16 +446,11 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
           }
         };
 
-        if ty::type_has_rptrs(typ) {
-            tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_has_regions);
-        } else {
-            tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_resolved(typ));
-        }
-
+        tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_resolved(typ));
         ret typ;
     }
 
-    ret do_ast_ty_to_ty(tcx, ast_ty.id, mode, ast_ty);
+    ret do_ast_ty_to_ty(tcx, mode, ast_ty);
 }
 
 fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
@@ -571,6 +538,37 @@ fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item)
       }
     }
 }
+
+type next_region_param_id = { mut id: uint };
+
+fn fixup_regions(tcx: ty::ctxt, next_region_param_id: next_region_param_id,
+                 ty: ty::t) -> ty::t {
+    let cur_region_param = @mut next_region_param_id.id;
+    ret ty::fold_ty(tcx, ty::fm_rptr({|region, under_rptr|
+        alt region {
+            ty::re_inferred {
+                if !under_rptr {
+                    *cur_region_param = next_region_param_id.id;
+                    next_region_param_id.id += 1u;
+                }
+                ty::re_param(*cur_region_param)
+            }
+            _ { region }
+        }
+    }), ty);
+}
+
+fn fixup_regions_to_block(tcx: ty::ctxt, ty: ty::t, ast_ty: @ast::ty)
+        -> ty::t {
+    let region = tcx.region_map.ast_type_to_inferred_region.get(ast_ty.id);
+    ret ty::fold_ty(tcx, ty::fm_rptr({|this_region, _under_rptr|
+        alt this_region {
+            ty::re_inferred { region }
+            _ { this_region }
+        }
+    }), ty);
+}
+
 fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg {
     fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode {
         alt m {
@@ -603,8 +601,38 @@ fn ty_of_fn_decl(tcx: ty::ctxt,
                  mode: mode,
                  proto: ast::proto,
                  decl: ast::fn_decl) -> ty::fn_ty {
-    let input_tys = vec::map(decl.inputs) {|a| ty_of_arg(tcx, mode, a) };
-    let output_ty = ast_ty_to_ty(tcx, mode, decl.output);
+    let mut has_regions: bool = false;
+    let mut max_region_param: @mut uint = @mut 0u;
+
+    let mut input_tys = vec::map(decl.inputs) {|a|
+        let arg_ty = ty_of_arg(tcx, mode, a);
+
+        if ty::type_has_rptrs(arg_ty.ty) {
+            has_regions = true;
+            let _ = ty::fold_ty(tcx, ty::fm_rptr({|r, _under_rptr|
+                alt r {
+                    ty::re_param(n) {
+                        *max_region_param = uint::max(n, *max_region_param);
+                    }
+                    _ { /* no-op */ }
+                };
+                r
+            }), arg_ty.ty);
+        }
+
+        arg_ty
+    };
+
+    let mut output_ty = ast_ty_to_ty(tcx, mode, decl.output);
+
+    if has_regions {
+        let next_region_param_id = { mut id: *max_region_param };
+        input_tys = vec::map(input_tys, {|input_ty|
+            {ty: fixup_regions(tcx, next_region_param_id, input_ty.ty)
+             with input_ty}
+        });
+        output_ty = fixup_regions(tcx, next_region_param_id, output_ty);
+    }
 
     let out_constrs = vec::map(decl.constraints) {|constr|
         ty::ast_constr_to_constr(tcx, constr)
@@ -843,9 +871,9 @@ fn fixup_self_in_method_ty(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t],
 fn fixup_self_region_in_method_ty(fcx: @fn_ctxt, mty: ty::t,
                                   self_expr: @ast::expr) -> ty::t {
     let self_region = region_of(fcx, self_expr);
-    ty::fold_ty(fcx.ccx.tcx, ty::fm_rptr({|r|
+    ty::fold_ty(fcx.ccx.tcx, ty::fm_rptr({|r, _under_rptr|
         alt r {
-            ty::re_self(_) { self_region }
+            ty::re_self { self_region }
             _ { r }
         }
     }), mty)
@@ -876,7 +904,13 @@ mod collect {
                 // should be called to resolve named types.
                 let mut args: [arg] = [];
                 for va: ast::variant_arg in variant.node.args {
-                    let arg_ty = ast_ty_to_ty(tcx, m_collect, va.ty);
+                    let mut arg_ty = ast_ty_to_ty(tcx, m_collect, va.ty);
+                    if ty::type_has_rptrs(arg_ty) {
+                        let next_region_param_id = { mut id: 0u };
+                        arg_ty = fixup_regions(tcx, next_region_param_id,
+                                               arg_ty);
+                    }
+
                     args += [{mode: ast::expl(ast::by_copy), ty: arg_ty}];
                 }
                 // FIXME: this will be different for constrained types
@@ -1504,8 +1538,16 @@ fn gather_locals(ccx: @crate_ctxt,
 
     // Add explicitly-declared locals.
     let visit_local = fn@(local: @ast::local, &&e: (), v: visit::vt<()>) {
-        let local_ty = ast_ty_to_ty_crate_infer(ccx, local.node.ty);
-        assign(local.node.id, local_ty);
+        let mut local_ty_opt = ast_ty_to_ty_crate_infer(ccx, local.node.ty);
+        alt local_ty_opt {
+            some(local_ty) if ty::type_has_rptrs(local_ty) {
+                local_ty_opt = some(fixup_regions_to_block(ccx.tcx, local_ty,
+                                                           local.node.ty));
+            }
+            _ { /* nothing to do */ }
+        }
+
+        assign(local.node.id, local_ty_opt);
         visit::visit_local(local, e, v);
     };
 
@@ -1571,10 +1613,9 @@ type pat_ctxt = {
 fn instantiate_self_regions(tcx: ty::ctxt, region: ty::region, &&ty: ty::t)
         -> ty::t {
     if ty::type_has_rptrs(ty) {
-        ty::fold_ty(tcx, ty::fm_rptr({|r|
+        ty::fold_ty(tcx, ty::fm_rptr({|r, _under_rptr|
             alt r {
-                // FIXME: Should not happen for re_param.
-                ty::re_param(_) | ty::re_caller(_) | ty::re_self(_) { region }
+                ty::re_inferred | ty::re_self | ty::re_param(_) { region }
                 _ { r }
             }
         }), ty)
@@ -1588,9 +1629,9 @@ fn instantiate_self_regions(tcx: ty::ctxt, region: ty::region, &&ty: ty::t)
 // refer to inferred regions.
 fn universally_quantify_regions(tcx: ty::ctxt, ty: ty::t) -> ty::t {
     if ty::type_has_rptrs(ty) {
-        ty::fold_ty(tcx, ty::fm_rptr({|_r|
-            // FIXME: Very wrong. Shouldn't be 0u.
-            ty::re_param(0u)
+        ty::fold_ty(tcx, ty::fm_rptr({|_r, _under_rptr|
+            // FIXME: Should these all be different variables?
+            ty::re_var(0u)
         }), ty)
     } else {
         ty
@@ -1606,7 +1647,7 @@ fn replace_region_params(tcx: ty::ctxt,
         -> ty::t {
 
     if ty::type_has_rptrs(ty) {
-        ty::fold_ty(tcx, ty::fm_rptr({ |r|
+        ty::fold_ty(tcx, ty::fm_rptr({ |r, _under_rptr|
             alt r {
                 ty::re_param(n) {
                     if n < ufind::set_count(rb.sets) {
@@ -2085,13 +2126,14 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
         for @{did, methods, _} in *impls {
             alt vec::find(methods, {|m| m.ident == name}) {
               some(m) {
-                let {n_tps, ty: self_ty} = impl_self_ty(tcx, did);
-                let {vars, ty: self_ty} = if n_tps > 0u {
+                let mut {n_tps, ty: self_ty} = impl_self_ty(tcx, did);
+                let mut {vars, ty: self_ty} = if n_tps > 0u {
                     bind_params(fcx, self_ty, n_tps)
                 } else {
                     {vars: [], ty: self_ty}
                 };
 
+                self_ty = universally_quantify_regions(tcx, self_ty);
                 let ty = universally_quantify_regions(tcx, ty);
 
                 alt unify::unify(fcx, self_ty, ty) {
@@ -2223,32 +2265,23 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
 
     // A generic function to factor out common logic from call and bind
     // expressions.
-    fn check_call_or_bind(fcx: @fn_ctxt, sp: span, id: ast::node_id,
-                          fty: ty::t, args: [option<@ast::expr>])
+    fn check_call_or_bind(fcx: @fn_ctxt, sp: span, fty: ty::t,
+                          args: [option<@ast::expr>])
             -> check_call_or_bind_result {
+
         // Replaces "caller" regions in the arguments with the local region.
-        fn instantiate_caller_regions(fcx: @fn_ctxt, id: ast::node_id,
-                                      args: [ty::arg]) -> [ty::arg] {
-            let site_to_block = fcx.ccx.tcx.region_map.call_site_to_block;
-            let block_id = alt site_to_block.find(id) {
-                none {
-                    // This can happen for those expressions that are
-                    // synthesized during typechecking; e.g. during
-                    // check_constraints().
-                    ret args;
-                }
-                some(block_id) { block_id }
-            };
+        fn instantiate_caller_regions(fcx: @fn_ctxt, args: [ty::arg])
+                -> [ty::arg] {
 
-            let region = ty::re_block(block_id);
             ret vec::map(args) {|arg|
                 if ty::type_has_rptrs(arg.ty) {
-                    let ty = ty::fold_ty(fcx.ccx.tcx, ty::fm_rptr({|r|
+                    let ty = ty::fold_ty(fcx.ccx.tcx,
+                                         ty::fm_rptr({|r, _under_rptr|
                         alt r {
-                            ty::re_caller(_) {
+                            ty::re_param(param) {
                                 // FIXME: We should not recurse into nested
                                 // function types here.
-                                region
+                                ty::re_var(param)
                             }
                             _ { r }
                         }
@@ -2301,7 +2334,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         }
 
         // FIXME: This should instantiate re_params instead.
-        arg_tys = instantiate_caller_regions(fcx, id, arg_tys);
+        arg_tys = instantiate_caller_regions(fcx, arg_tys);
 
         // Check the arguments.
         // We do this in a pretty awful way: first we typecheck any arguments
@@ -2344,8 +2377,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
     }
 
     // A generic function for checking call expressions
-    fn check_call(fcx: @fn_ctxt, sp: span, id: ast::node_id, f: @ast::expr,
-                  args: [@ast::expr])
+    fn check_call(fcx: @fn_ctxt, sp: span, f: @ast::expr, args: [@ast::expr])
             -> check_call_or_bind_result {
         let mut args_opt_0: [option<@ast::expr>] = [];
         for arg: @ast::expr in args {
@@ -2354,7 +2386,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
 
         let bot = check_expr(fcx, f);
         // Call the generic checker.
-        let ccobr = check_call_or_bind(fcx, sp, id, expr_ty(fcx.ccx.tcx, f),
+        let ccobr = check_call_or_bind(fcx, sp, expr_ty(fcx.ccx.tcx, f),
                                        args_opt_0);
         ret { bot: bot | ccobr.bot with ccobr };
     }
@@ -2362,7 +2394,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
     // A generic function for doing all of the checking for call expressions
     fn check_call_full(fcx: @fn_ctxt, sp: span, id: ast::node_id,
                        f: @ast::expr, args: [@ast::expr]) -> bool {
-        let ccobr = check_call(fcx, sp, id, f, args);
+        let ccobr = check_call(fcx, sp, f, args);
         let mut bot = ccobr.bot;
         /* need to restrict oper to being an explicit expr_path if we're
         inside a pure function */
@@ -2443,7 +2475,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         alt lookup_method(fcx, op_ex, callee_id, opname, self_t, []) {
           some(origin) {
             let method_ty = ty::node_id_to_type(fcx.ccx.tcx, callee_id);
-            check_call_or_bind(fcx, op_ex.span, op_ex.id, method_ty, args);
+            check_call_or_bind(fcx, op_ex.span, method_ty, args);
             fcx.ccx.method_map.insert(op_ex.id, origin);
             some(ty::ty_fn_ret(method_ty))
           }
@@ -2773,8 +2805,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
       ast::expr_bind(f, args) {
         // Call the generic checker.
         bot = check_expr(fcx, f);
-        let ccobr = check_call_or_bind(fcx, expr.span, expr.id,
-                                       expr_ty(tcx, f), args);
+        let ccobr = check_call_or_bind(fcx, expr.span, expr_ty(tcx, f), args);
         bot |= ccobr.bot;
 
         // TODO: Perform substitutions on the return type.
@@ -3482,9 +3513,9 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
         check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none);
       }
       ast::item_impl(tps, _, ty, ms) {
-        let self_ty = ast_ty_to_ty(ccx.tcx, m_check, ty);
-        let self_region = ty::re_self({crate: ast::local_crate, node: it.id});
-        let self_ty = instantiate_self_regions(ccx.tcx, self_region, self_ty);
+        let mut self_ty = ast_ty_to_ty(ccx.tcx, m_check, ty);
+        let self_region = ty::re_self;
+        self_ty = instantiate_self_regions(ccx.tcx, self_region, self_ty);
         ccx.self_infos += [self_impl(self_ty)];
         for m in ms { check_method(ccx, m); }
         vec::pop(ccx.self_infos);
diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs
index 9cfd0299919..032f3620631 100644
--- a/src/rustc/util/ppaux.rs
+++ b/src/rustc/util/ppaux.rs
@@ -12,20 +12,6 @@ import driver::session::session;
 
 fn region_to_str(cx: ctxt, region: region) -> str {
     alt region {
-      re_named(_)   { "<name>" }    // TODO: include name
-      re_caller(def_id) {
-        if def_id.crate == ast::local_crate {
-            alt cx.items.get(def_id.node) {
-              ast_map::node_item(item, path) {
-                #fmt("<caller of %s::%s>", ast_map::path_to_str(*path),
-                     item.ident)
-              }
-              _ { "<caller>" }
-            }
-        } else {
-            "<caller>"
-        }
-      }
       re_block(node_id) {
         alt cx.items.get(node_id) {
             ast_map::node_block(blk) {
@@ -35,8 +21,10 @@ fn region_to_str(cx: ctxt, region: region) -> str {
             _ { cx.sess.bug("re_block refers to non-block") }
         }
       }
-      re_self(_)    { "self" }
+      re_self       { "self" }
       re_inferred   { "" }
+      re_param(id)  { #fmt("<P%u>", id) }    // TODO: do better than this
+      re_var(id)    { #fmt("<R%u>", id) }    // TODO: do better than this
     }
 }