about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-01-08 14:00:45 -0800
committerNiko Matsakis <niko@alum.mit.edu>2013-01-09 14:59:07 -0800
commit2b92962aa29b0116015f99c1666ecf6288303c65 (patch)
treeb4d84abe1587cddd4db8fcece762f43a89f4bec7 /src
parent11a307294a83c2651405137763c9d620ab3fc7e7 (diff)
downloadrust-2b92962aa29b0116015f99c1666ecf6288303c65.tar.gz
rust-2b92962aa29b0116015f99c1666ecf6288303c65.zip
A collection of refactorings that I found it hard/tiresome to divide:
- Make `extern fn()` assignable to any closure type, rather than
  a subtype.
- Remove unused int_ty_set and float_ty_set
- Refactor variable unification and make it more DRY
- Do fn sub/lub/glb on the level of fn_sig
- Rename infer::to_str::ToStr to infer::to_str::InferStr
- Capitalize names of various types
- Correct hashing of FnMeta
- Convert various records-of-fns into structs-of-fns.  This is both
  eliminating use of deprecated features and more forwards compatible
  with fn reform.

r=pcwalton
Diffstat (limited to 'src')
-rw-r--r--src/compiletest/compiletest.rc2
-rw-r--r--src/libcargo/cargo.rc2
-rw-r--r--src/libcore/stackwalk.rs2
-rw-r--r--src/libfuzzer/fuzzer.rc11
-rw-r--r--src/librustc/driver/driver.rs11
-rw-r--r--src/librustc/front/config.rs4
-rw-r--r--src/librustc/front/core_inject.rs2
-rw-r--r--src/librustc/front/test.rs16
-rw-r--r--src/librustc/metadata/creader.rs8
-rw-r--r--src/librustc/metadata/encoder.rs48
-rw-r--r--src/librustc/metadata/tyencode.rs7
-rw-r--r--src/librustc/middle/astencode.rs14
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs14
-rw-r--r--src/librustc/middle/borrowck/gather_loans.rs6
-rw-r--r--src/librustc/middle/borrowck/mod.rs1
-rw-r--r--src/librustc/middle/check_const.rs4
-rw-r--r--src/librustc/middle/check_loop.rs2
-rw-r--r--src/librustc/middle/check_match.rs4
-rw-r--r--src/librustc/middle/const_eval.rs2
-rw-r--r--src/librustc/middle/freevars.rs10
-rw-r--r--src/librustc/middle/kind.rs2
-rw-r--r--src/librustc/middle/lang_items.rs4
-rw-r--r--src/librustc/middle/lint.rs129
-rw-r--r--src/librustc/middle/liveness.rs4
-rw-r--r--src/librustc/middle/mode.rs2
-rw-r--r--src/librustc/middle/privacy.rs2
-rw-r--r--src/librustc/middle/region.rs4
-rw-r--r--src/librustc/middle/resolve.rs6
-rw-r--r--src/librustc/middle/trans/base.rs10
-rw-r--r--src/librustc/middle/trans/callee.rs2
-rw-r--r--src/librustc/middle/trans/reachable.rs39
-rw-r--r--src/librustc/middle/trans/type_use.rs2
-rw-r--r--src/librustc/middle/ty.rs204
-rw-r--r--src/librustc/middle/typeck/check/method.rs2
-rw-r--r--src/librustc/middle/typeck/check/mod.rs91
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs13
-rw-r--r--src/librustc/middle/typeck/check/regionmanip.rs57
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs10
-rw-r--r--src/librustc/middle/typeck/check/writeback.rs21
-rw-r--r--src/librustc/middle/typeck/coherence.rs13
-rw-r--r--src/librustc/middle/typeck/collect.rs12
-rw-r--r--src/librustc/middle/typeck/infer/assignment.rs42
-rw-r--r--src/librustc/middle/typeck/infer/combine.rs136
-rw-r--r--src/librustc/middle/typeck/infer/floating.rs64
-rw-r--r--src/librustc/middle/typeck/infer/glb.rs48
-rw-r--r--src/librustc/middle/typeck/infer/integral.rs95
-rw-r--r--src/librustc/middle/typeck/infer/lattice.rs509
-rw-r--r--src/librustc/middle/typeck/infer/lub.rs49
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs203
-rw-r--r--src/librustc/middle/typeck/infer/region_inference.rs7
-rw-r--r--src/librustc/middle/typeck/infer/resolve.rs170
-rw-r--r--src/librustc/middle/typeck/infer/sub.rs111
-rw-r--r--src/librustc/middle/typeck/infer/to_str.rs93
-rw-r--r--src/librustc/middle/typeck/infer/unify.rs529
-rw-r--r--src/librustc/middle/typeck/mod.rs2
-rw-r--r--src/librustc/util/common.rs10
-rw-r--r--src/librustc/util/ppaux.rs26
-rw-r--r--src/librustdoc/attr_pass.rs2
-rw-r--r--src/librustdoc/desc_to_brief_pass.rs2
-rw-r--r--src/librustdoc/markdown_index_pass.rs2
-rw-r--r--src/librustdoc/markdown_pass.rs2
-rw-r--r--src/librustdoc/page_pass.rs2
-rw-r--r--src/librustdoc/pass.rs8
-rw-r--r--src/librustdoc/path_pass.rs2
-rw-r--r--src/librustdoc/prune_hidden_pass.rs2
-rw-r--r--src/librustdoc/prune_private_pass.rs2
-rw-r--r--src/librustdoc/sectionalize_pass.rs2
-rw-r--r--src/librustdoc/sort_pass.rs2
-rw-r--r--src/librustdoc/text_pass.rs2
-rw-r--r--src/librustdoc/tystr_pass.rs2
-rw-r--r--src/libstd/test.rs41
-rw-r--r--src/libsyntax/ast.rs38
-rw-r--r--src/libsyntax/ast_map.rs2
-rw-r--r--src/libsyntax/ast_util.rs6
-rw-r--r--src/libsyntax/ext/expand.rs14
-rw-r--r--src/libsyntax/fold.rs18
-rw-r--r--src/libsyntax/print/pprust.rs7
-rw-r--r--src/libsyntax/visit.rs224
-rw-r--r--src/test/auxiliary/cci_nested_lib.rs6
-rw-r--r--src/test/compile-fail/block-coerce-no-2.rs2
-rw-r--r--src/test/compile-fail/borrowck-autoref-3261.rs4
-rw-r--r--src/test/compile-fail/main-wrong-type-2.rs2
-rw-r--r--src/test/compile-fail/main-wrong-type.rs2
-rw-r--r--src/test/compile-fail/missing-do.rs2
-rw-r--r--src/test/run-pass/fn-coerce-field.rs6
-rw-r--r--src/test/run-pass/intrinsic-frame-address.rs2
-rw-r--r--src/test/run-pass/issue-1458.rs2
87 files changed, 1642 insertions, 1661 deletions
diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rc
index 8505e481638..ba6862039d4 100644
--- a/src/compiletest/compiletest.rc
+++ b/src/compiletest/compiletest.rc
@@ -211,7 +211,7 @@ fn is_test(config: config, testfile: &Path) -> bool {
 
 fn make_test(config: config, testfile: &Path) ->
    test::TestDesc {
-    {
+    test::TestDesc {
         name: make_test_name(config, testfile),
         testfn: make_test_closure(config, testfile),
         ignore: header::is_test_ignored(config, testfile),
diff --git a/src/libcargo/cargo.rc b/src/libcargo/cargo.rc
index f588f3643ce..ea67d0ea858 100644
--- a/src/libcargo/cargo.rc
+++ b/src/libcargo/cargo.rc
@@ -403,7 +403,7 @@ fn load_crate(filename: &Path) -> Option<Crate> {
     let e = @{
         mut deps: ~[]
     };
-    let v = visit::mk_simple_visitor(@{
+    let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
         visit_view_item: |a| goto_view_item(sess, e, a),
         visit_item: |a| goto_item(e, a),
         .. *visit::default_simple_visitor()
diff --git a/src/libcore/stackwalk.rs b/src/libcore/stackwalk.rs
index 1beb1a56efa..f45f71104f4 100644
--- a/src/libcore/stackwalk.rs
+++ b/src/libcore/stackwalk.rs
@@ -99,5 +99,5 @@ extern mod rustrt {
 #[abi = "rust-intrinsic"]
 extern mod rusti {
     #[legacy_exports];
-    fn frame_address(f: fn(++x: *u8));
+    fn frame_address(f: &once fn(++x: *u8));
 }
diff --git a/src/libfuzzer/fuzzer.rc b/src/libfuzzer/fuzzer.rc
index 5f954558668..fd36c1d7701 100644
--- a/src/libfuzzer/fuzzer.rc
+++ b/src/libfuzzer/fuzzer.rc
@@ -167,7 +167,7 @@ type stolen_stuff = {exprs: ~[ast::expr], tys: ~[ast::Ty]};
 fn steal(crate: ast::crate, tm: test_mode) -> stolen_stuff {
     let exprs = @mut ~[];
     let tys = @mut ~[];
-    let v = visit::mk_simple_visitor(@{
+    let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
         visit_expr: |a| stash_expr_if(safe_to_steal_expr, exprs, a, tm),
         visit_ty: |a| stash_ty_if(safe_to_steal_ty, tys, a, tm),
         .. *visit::default_simple_visitor()
@@ -216,7 +216,7 @@ fn replace_expr_in_crate(crate: ast::crate, i: uint,
             fold::noop_fold_expr(original, fld)
         }
     }
-    let afp = @{
+    let afp = @fold::AstFoldFns {
         fold_expr: fold::wrap(|a,b| {
             fold_expr_rep(j, i, newexpr.node, a, b, tm)
         }),
@@ -241,7 +241,7 @@ fn replace_ty_in_crate(crate: ast::crate, i: uint, newty: ast::Ty,
             newty_
         } else { fold::noop_fold_ty(original, fld) }
     }
-    let afp = @{
+    let afp = @fold::AstFoldFns {
         fold_ty: fold::wrap(|a,b| fold_ty_rep(j, i, newty.node, a, b, tm) ),
         .. *fold::default_ast_fold()
     };
@@ -486,8 +486,9 @@ fn has_raw_pointers(c: ast::crate) -> bool {
         }
     }
     let v =
-        visit::mk_simple_visitor(@{visit_ty: |a| visit_ty(has_rp, a),
-                                      .. *visit::default_simple_visitor()});
+        visit::mk_simple_visitor(@visit::SimpleVisitor {
+            visit_ty: |a| visit_ty(has_rp, a),
+            .. *visit::default_simple_visitor()});
     visit::visit_crate(c, (), v);
     return *has_rp;
 }
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index cbc598228a4..b4a9a83992d 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -395,13 +395,16 @@ fn pretty_print_input(sess: Session, +cfg: ast::crate_cfg, input: input,
 
     let ann = match ppm {
       ppm_typed => {
-        {pre: ann_paren_for_expr,
-         post: |a| ann_typed_post(tcx.get(), a) }
+          pprust::pp_ann {pre: ann_paren_for_expr,
+                          post: |a| ann_typed_post(tcx.get(), a) }
       }
       ppm_identified | ppm_expanded_identified => {
-        {pre: ann_paren_for_expr, post: ann_identified_post}
+          pprust::pp_ann {pre: ann_paren_for_expr,
+                          post: ann_identified_post}
+      }
+      ppm_expanded | ppm_normal => {
+          pprust::no_ann()
       }
-      ppm_expanded | ppm_normal => pprust::no_ann()
     };
     let is_expanded = upto != cu_parse;
     let src = sess.codemap.get_filemap(source_name(input)).src;
diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs
index 10c2f2e65f1..307698af037 100644
--- a/src/librustc/front/config.rs
+++ b/src/librustc/front/config.rs
@@ -38,8 +38,8 @@ fn strip_items(crate: @ast::crate, in_cfg: in_cfg_pred)
 
     let ctxt = @{in_cfg: in_cfg};
 
-    let precursor =
-        @{fold_mod: |a,b| fold_mod(ctxt, a, b),
+    let precursor = @fold::AstFoldFns {
+          fold_mod: |a,b| fold_mod(ctxt, a, b),
           fold_block: fold::wrap(|a,b| fold_block(ctxt, a, b) ),
           fold_foreign_mod: |a,b| fold_foreign_mod(ctxt, a, b),
           fold_item_underscore: |a,b| {
diff --git a/src/librustc/front/core_inject.rs b/src/librustc/front/core_inject.rs
index 772bd39e07b..045e60052a4 100644
--- a/src/librustc/front/core_inject.rs
+++ b/src/librustc/front/core_inject.rs
@@ -42,7 +42,7 @@ fn inject_libcore_ref(sess: Session,
         ast::spanned { node: x, span: dummy_sp() }
     }
 
-    let precursor = @{
+    let precursor = @fold::AstFoldFns {
         fold_crate: |crate, span, fld| {
             let n1 = sess.next_node_id();
             let vi1 = @{node: ast::view_item_use(sess.ident_of(~"core"),
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
index 497a6878bc1..970f1a065a7 100644
--- a/src/librustc/front/test.rs
+++ b/src/librustc/front/test.rs
@@ -65,10 +65,10 @@ fn generate_test_harness(sess: session::Session,
           mut path: ~[],
           testfns: DVec()};
 
-    let precursor =
-        @{fold_crate: fold::wrap(|a,b| fold_crate(cx, a, b) ),
-          fold_item: |a,b| fold_item(cx, a, b),
-          fold_mod: |a,b| fold_mod(cx, a, b),.. *fold::default_ast_fold()};
+    let precursor = @fold::AstFoldFns {
+        fold_crate: fold::wrap(|a,b| fold_crate(cx, a, b) ),
+        fold_item: |a,b| fold_item(cx, a, b),
+        fold_mod: |a,b| fold_mod(cx, a, b),.. *fold::default_ast_fold()};
 
     let fold = fold::make_fold(precursor);
     let res = @fold.fold_crate(*crate);
@@ -424,8 +424,14 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {
                 ident: cx.sess.ident_of(~"should_fail"),
                 expr: @fail_expr});
 
+    let test_desc_path =
+        mk_path(cx, ~[cx.sess.ident_of(~"test"),
+                      cx.sess.ident_of(~"TestDesc")]);
+
     let desc_rec_: ast::expr_ =
-        ast::expr_rec(~[name_field, fn_field, ignore_field, fail_field],
+        ast::expr_struct(
+            test_desc_path,
+            ~[name_field, fn_field, ignore_field, fail_field],
             option::None);
     let desc_rec: ast::expr =
         {id: cx.sess.next_node_id(), callee_id: cx.sess.next_node_id(),
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index 078b5ea9a4b..a731aa8db97 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -52,10 +52,10 @@ fn read_crates(diag: span_handler,
               mut next_crate_num: 1,
               intr: intr};
     let v =
-        visit::mk_simple_visitor(@{visit_view_item:
-                                       |a| visit_view_item(e, a),
-                                   visit_item: |a| visit_item(e, a)
-                                   ,.. *visit::default_simple_visitor()});
+        visit::mk_simple_visitor(@visit::SimpleVisitor {
+            visit_view_item: |a| visit_view_item(e, a),
+            visit_item: |a| visit_item(e, a),
+            .. *visit::default_simple_visitor()});
     visit::visit_crate(crate, (), v);
     dump_crates(e.crate_cache);
     warn_if_multiple_versions(e, diag, e.crate_cache.get());
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index f52c2e448fe..6d131a074eb 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -180,11 +180,12 @@ fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) }
 
 fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, ecx: @encode_ctxt,
                                params: @~[ty::param_bounds]) {
-    let ty_str_ctxt = @{diag: ecx.diag,
-                        ds: def_to_str,
-                        tcx: ecx.tcx,
-                        reachable: |a| reachable(ecx, a),
-                        abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
+    let ty_str_ctxt = @tyencode::ctxt {
+        diag: ecx.diag,
+        ds: def_to_str,
+        tcx: ecx.tcx,
+        reachable: |a| reachable(ecx, a),
+        abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
     for params.each |param| {
         ebml_w.start_tag(tag_items_data_item_ty_param_bounds);
         tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, *param);
@@ -207,23 +208,23 @@ fn encode_variant_id(ebml_w: writer::Encoder, vid: def_id) {
 }
 
 fn write_type(ecx: @encode_ctxt, ebml_w: writer::Encoder, typ: ty::t) {
-    let ty_str_ctxt =
-        @{diag: ecx.diag,
-          ds: def_to_str,
-          tcx: ecx.tcx,
-          reachable: |a| reachable(ecx, a),
-          abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
+    let ty_str_ctxt = @tyencode::ctxt {
+        diag: ecx.diag,
+        ds: def_to_str,
+        tcx: ecx.tcx,
+        reachable: |a| reachable(ecx, a),
+        abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
     tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ);
 }
 
 fn write_vstore(ecx: @encode_ctxt, ebml_w: writer::Encoder,
                 vstore: ty::vstore) {
-    let ty_str_ctxt =
-        @{diag: ecx.diag,
-          ds: def_to_str,
-          tcx: ecx.tcx,
-          reachable: |a| reachable(ecx, a),
-          abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
+    let ty_str_ctxt = @tyencode::ctxt {
+        diag: ecx.diag,
+        ds: def_to_str,
+        tcx: ecx.tcx,
+        reachable: |a| reachable(ecx, a),
+        abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
     tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore);
 }
 
@@ -887,7 +888,7 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: writer::Encoder,
     encode_info_for_mod(ecx, ebml_w, crate.node.module,
                         crate_node_id, ~[],
                         syntax::parse::token::special_idents::invalid);
-    visit::visit_crate(*crate, (), visit::mk_vt(@{
+    visit::visit_crate(*crate, (), visit::mk_vt(@visit::Visitor {
         visit_expr: |_e, _cx, _v| { },
         visit_item: |i, cx, v, copy ebml_w| {
             visit::visit_item(i, cx, v);
@@ -1267,11 +1268,12 @@ fn encode_metadata(parms: encode_parms, crate: @crate) -> ~[u8] {
 
 // Get the encoded string for a type
 fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str {
-    let cx = @{diag: tcx.diag,
-               ds: def_to_str,
-               tcx: tcx,
-               reachable: |_id| false,
-               abbrevs: tyencode::ac_no_abbrevs};
+    let cx = @tyencode::ctxt {
+        diag: tcx.diag,
+        ds: def_to_str,
+        tcx: tcx,
+        reachable: |_id| false,
+        abbrevs: tyencode::ac_no_abbrevs};
     do io::with_str_writer |wr| {
         tyencode::enc_ty(wr, cx, t);
     }
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 67f168cc5b6..154fb8d2de8 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -14,7 +14,7 @@
 use core::prelude::*;
 
 use middle::ty;
-use middle::ty::vid;
+use middle::ty::Vid;
 
 use core::io::WriterUtil;
 use core::io;
@@ -24,6 +24,7 @@ use std::map::HashMap;
 use syntax::ast::*;
 use syntax::diagnostic::span_handler;
 use syntax::print::pprust::*;
+use middle::ty::Vid;
 
 export ctxt;
 export ty_abbrev;
@@ -35,7 +36,7 @@ export enc_mode;
 export enc_arg;
 export enc_vstore;
 
-type ctxt = {
+struct ctxt {
     diag: span_handler,
     // Def -> str Callback:
     ds: fn@(def_id) -> ~str,
@@ -43,7 +44,7 @@ type ctxt = {
     tcx: ty::ctxt,
     reachable: fn@(node_id) -> bool,
     abbrevs: abbrev_ctxt
-};
+}
 
 // Compact string representation for ty.t values. API ty_str & parse_from_str.
 // Extra parameters are for converting to/from def_ids in the string rep.
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 9b024f87f41..eb9d4ae6a30 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -271,7 +271,7 @@ fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item {
         fold::noop_fold_block(blk_sans_items, fld)
     }
 
-    let fld = fold::make_fold(@{
+    let fld = fold::make_fold(@fold::AstFoldFns {
         fold_block: fold::wrap(drop_nested_items),
         .. *fold::default_ast_fold()
     });
@@ -304,7 +304,7 @@ fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item {
 
 fn renumber_ast(xcx: extended_decode_ctxt, ii: ast::inlined_item)
     -> ast::inlined_item {
-    let fld = fold::make_fold(@{
+    let fld = fold::make_fold(@fold::AstFoldFns{
         new_id: |a| xcx.tr_id(a),
         new_span: |a| xcx.tr_span(a),
         .. *fold::default_ast_fold()
@@ -643,11 +643,11 @@ trait get_ty_str_ctxt {
 
 impl @e::encode_ctxt: get_ty_str_ctxt {
     fn ty_str_ctxt() -> @tyencode::ctxt {
-        @{diag: self.tcx.sess.diagnostic(),
-          ds: e::def_to_str,
-          tcx: self.tcx,
-          reachable: |a| encoder::reachable(self, a),
-          abbrevs: tyencode::ac_use_abbrevs(self.type_abbrevs)}
+        @tyencode::ctxt {diag: self.tcx.sess.diagnostic(),
+                        ds: e::def_to_str,
+                        tcx: self.tcx,
+                        reachable: |a| encoder::reachable(self, a),
+                        abbrevs: tyencode::ac_use_abbrevs(self.type_abbrevs)}
     }
 }
 
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index 534098d96dc..3d5bdac596b 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -92,11 +92,11 @@ fn check_loans(bccx: borrowck_ctxt,
                                  reported: HashMap(),
                                  mut declared_purity: ast::impure_fn,
                                  mut fn_args: @~[]});
-    let vt = visit::mk_vt(@{visit_expr: check_loans_in_expr,
-                            visit_local: check_loans_in_local,
-                            visit_block: check_loans_in_block,
-                            visit_fn: check_loans_in_fn,
-                            .. *visit::default_visitor()});
+    let vt = visit::mk_vt(@visit::Visitor {visit_expr: check_loans_in_expr,
+                                           visit_local: check_loans_in_local,
+                                           visit_block: check_loans_in_block,
+                                           visit_fn: check_loans_in_fn,
+                                           .. *visit::default_visitor()});
     visit::visit_crate(*crate, clcx, vt);
 }
 
@@ -247,13 +247,13 @@ impl check_loan_ctxt {
         let callee_ty = ty::node_id_to_type(tcx, callee_id);
         match ty::get(callee_ty).sty {
           ty::ty_fn(ref fn_ty) => {
-            match (*fn_ty).meta.purity {
+            match fn_ty.meta.purity {
               ast::pure_fn => return, // case (c) above
               ast::impure_fn | ast::unsafe_fn | ast::extern_fn => {
                 self.report_purity_error(
                     pc, callee_span,
                     fmt!("access to %s function",
-                         pprust::purity_to_str((*fn_ty).meta.purity)));
+                         fn_ty.meta.purity.to_str()));
               }
             }
           }
diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs
index 215256a8e95..52cbd1da10c 100644
--- a/src/librustc/middle/borrowck/gather_loans.rs
+++ b/src/librustc/middle/borrowck/gather_loans.rs
@@ -82,9 +82,9 @@ fn gather_loans(bccx: borrowck_ctxt, crate: @ast::crate) -> req_maps {
                                   mut item_ub: 0,
                                   mut root_ub: 0,
                                   mut ignore_adjustments: LinearMap()});
-    let v = visit::mk_vt(@{visit_expr: req_loans_in_expr,
-                           visit_fn: req_loans_in_fn,
-                           .. *visit::default_visitor()});
+    let v = visit::mk_vt(@visit::Visitor {visit_expr: req_loans_in_expr,
+                                          visit_fn: req_loans_in_fn,
+                                          .. *visit::default_visitor()});
     visit::visit_crate(*crate, glcx, v);
     return glcx.req_maps;
 }
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index a6fbe5bd6dd..19fc9eb175d 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -231,7 +231,6 @@ use core::prelude::*;
 use middle::liveness;
 use middle::mem_categorization::*;
 use middle::region;
-use middle::ty::to_str;
 use middle::ty;
 use util::common::indenter;
 use util::ppaux::{expr_repr, note_and_explain_region};
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 0166c8da410..7986352cac2 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -25,7 +25,7 @@ use syntax::{visit, ast_util, ast_map};
 fn check_crate(sess: Session, crate: @crate, ast_map: ast_map::map,
                def_map: resolve::DefMap,
                 method_map: typeck::method_map, tcx: ty::ctxt) {
-    visit::visit_crate(*crate, false, visit::mk_vt(@{
+    visit::visit_crate(*crate, false, visit::mk_vt(@visit::Visitor {
         visit_item: |a,b,c| check_item(sess, ast_map, def_map, a, b, c),
         visit_pat: check_pat,
         visit_expr: |a,b,c|
@@ -211,7 +211,7 @@ fn check_item_recursion(sess: Session, ast_map: ast_map::map,
         idstack: @DVec()
     };
 
-    let visitor = visit::mk_vt(@{
+    let visitor = visit::mk_vt(@visit::Visitor {
         visit_item: visit_item,
         visit_expr: visit_expr,
         .. *visit::default_visitor()
diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs
index 88443843270..0e260c54fe2 100644
--- a/src/librustc/middle/check_loop.rs
+++ b/src/librustc/middle/check_loop.rs
@@ -19,7 +19,7 @@ type ctx = {in_loop: bool, can_ret: bool};
 fn check_crate(tcx: ty::ctxt, crate: @crate) {
     visit::visit_crate(*crate,
                        {in_loop: false, can_ret: true},
-                       visit::mk_vt(@{
+                       visit::mk_vt(@visit::Visitor {
         visit_item: |i, _cx, v| {
             visit::visit_item(i, {in_loop: false, can_ret: true}, v);
         },
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 441e800f36f..c99b5757baa 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -38,7 +38,7 @@ struct MatchCheckCtxt {
 
 fn check_crate(tcx: ty::ctxt, method_map: method_map, crate: @crate) {
     let cx = @MatchCheckCtxt { tcx: tcx, method_map: method_map };
-    visit::visit_crate(*crate, (), visit::mk_vt(@{
+    visit::visit_crate(*crate, (), visit::mk_vt(@visit::Visitor {
         visit_expr: |a,b,c| check_expr(cx, a, b, c),
         visit_local: |a,b,c| check_local(cx, a, b, c),
         visit_fn: |kind, decl, body, sp, id, e, v|
@@ -797,7 +797,7 @@ fn check_legality_of_move_bindings(cx: @MatchCheckCtxt,
 
         // Now check to ensure that any move binding is not behind an @ or &.
         // This is always illegal.
-        let vt = visit::mk_vt(@{
+        let vt = visit::mk_vt(@visit::Visitor {
             visit_pat: |pat, behind_bad_pointer, v| {
                 let error_out = || {
                     cx.tcx.sess.span_err(pat.span, ~"by-move pattern \
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 5821bf4fbe5..530e63acf57 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -207,7 +207,7 @@ fn lookup_constness(tcx: ty::ctxt, e: @expr) -> constness {
 fn process_crate(crate: @ast::crate,
                  def_map: resolve::DefMap,
                  tcx: ty::ctxt) {
-    let v = visit::mk_simple_visitor(@{
+    let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
         visit_expr_post: |e| { classify(e, def_map, tcx); },
         .. *visit::default_simple_visitor()
     });
diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs
index 9b718ec3bee..3c1f261c1f8 100644
--- a/src/librustc/middle/freevars.rs
+++ b/src/librustc/middle/freevars.rs
@@ -90,8 +90,9 @@ fn collect_freevars(def_map: resolve::DefMap, blk: ast::blk)
             }
         };
 
-    let v = visit::mk_vt(@{visit_item: ignore_item, visit_expr: walk_expr,
-                           .. *visit::default_visitor()});
+    let v = visit::mk_vt(@visit::Visitor {visit_item: ignore_item,
+                                          visit_expr: walk_expr,
+                                          .. *visit::default_visitor()});
     (v.visit_block)(blk, 1, v);
     return @/*bad*/copy *refs;
 }
@@ -112,8 +113,9 @@ fn annotate_freevars(def_map: resolve::DefMap, crate: @ast::crate) ->
     };
 
     let visitor =
-        visit::mk_simple_visitor(@{visit_fn: walk_fn,
-                                   .. *visit::default_simple_visitor()});
+        visit::mk_simple_visitor(@visit::SimpleVisitor {
+            visit_fn: walk_fn,
+            .. *visit::default_simple_visitor()});
     visit::visit_crate(*crate, (), visitor);
 
     return freevars;
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index 5e7002af2a5..3af1d7ea35b 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -97,7 +97,7 @@ fn check_crate(tcx: ty::ctxt,
                method_map: method_map,
                last_use_map: last_use_map,
                current_item: -1};
-    let visit = visit::mk_vt(@{
+    let visit = visit::mk_vt(@visit::Visitor {
         visit_arm: check_arm,
         visit_expr: check_expr,
         visit_stmt: check_stmt,
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index cca71153a7d..6870082ffac 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -29,7 +29,7 @@ use metadata::decoder::{dl_def, dl_field, dl_impl};
 use syntax::ast::{crate, def_fn, def_id, def_ty, lit_str, meta_item};
 use syntax::ast::{meta_list, meta_name_value, meta_word};
 use syntax::ast_util::{local_def};
-use syntax::visit::{default_simple_visitor, mk_simple_visitor};
+use syntax::visit::{default_simple_visitor, mk_simple_visitor, SimpleVisitor};
 use syntax::visit::{visit_crate, visit_item};
 
 use core::ptr;
@@ -333,7 +333,7 @@ impl LanguageItemCollector {
 
     fn collect_local_language_items() {
         let this = unsafe { ptr::addr_of(&self) };
-        visit_crate(*self.crate, (), mk_simple_visitor(@{
+        visit_crate(*self.crate, (), mk_simple_visitor(@SimpleVisitor {
             visit_item: |item| {
                 for item.attrs.each |attribute| {
                     unsafe {
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index 1db7e666ffb..b2881abf53b 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -430,7 +430,7 @@ fn build_settings_crate(sess: session::Session, crate: @ast::crate) {
 
         let cx = ctxt_({is_default: true,.. *cx});
 
-        let visit = visit::mk_vt(@{
+        let visit = visit::mk_vt(@visit::Visitor {
             visit_item: build_settings_item,
             .. *visit::default_visitor()
         });
@@ -458,30 +458,33 @@ fn check_item(i: @ast::item, cx: ty::ctxt) {
 // not traverse into subitems, since that is handled by the outer
 // lint visitor.
 fn item_stopping_visitor<E>(v: visit::vt<E>) -> visit::vt<E> {
-    visit::mk_vt(@{visit_item: |_i, _e, _v| { },.. **v})
+    visit::mk_vt(@visit::Visitor {visit_item: |_i, _e, _v| { },.. **v})
 }
 
 fn check_item_while_true(cx: ty::ctxt, it: @ast::item) {
-    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
-        visit_expr: fn@(e: @ast::expr) {
-           match e.node {
-             ast::expr_while(cond, _) => {
-                match cond.node {
-                    ast::expr_lit(@ast::spanned { node: ast::lit_bool(true),
-                                                  _}) => {
-                            cx.sess.span_lint(
-                                while_true, e.id, it.id,
-                                e.span,
-                                ~"denote infinite loops with loop { ... }");
+    let visit = item_stopping_visitor(
+        visit::mk_simple_visitor(@visit::SimpleVisitor {
+            visit_expr: |e: @ast::expr| {
+                match e.node {
+                    ast::expr_while(cond, _) => {
+                        match cond.node {
+                            ast::expr_lit(@ast::spanned {
+                                node: ast::lit_bool(true), _}) =>
+                            {
+                                cx.sess.span_lint(
+                                    while_true, e.id, it.id,
+                                    e.span,
+                                    ~"denote infinite loops \
+                                      with loop { ... }");
+                            }
+                            _ => ()
+                        }
                     }
                     _ => ()
                 }
-             }
-             _ => ()
-          }
-        },
-        .. *visit::default_simple_visitor()
-    }));
+            },
+            .. *visit::default_simple_visitor()
+        }));
     visit::visit_item(it, (), visit);
 }
 
@@ -596,10 +599,11 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) {
         }
     };
 
-    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
-        visit_expr: visit_expr,
-        .. *visit::default_simple_visitor()
-    }));
+    let visit = item_stopping_visitor(
+        visit::mk_simple_visitor(@visit::SimpleVisitor {
+            visit_expr: visit_expr,
+            .. *visit::default_simple_visitor()
+        }));
     visit::visit_item(it, (), visit);
 }
 
@@ -660,19 +664,20 @@ fn check_item_deprecated_self(cx: ty::ctxt, item: @ast::item) {
 }
 
 fn check_item_structural_records(cx: ty::ctxt, it: @ast::item) {
-    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
-        visit_expr: fn@(e: @ast::expr) {
-           match e.node {
-             ast::expr_rec(*) =>
-                 cx.sess.span_lint(
-                                structural_records, e.id, it.id,
-                                e.span,
-                                ~"structural records are deprecated"),
-               _ => ()
-           }
-        },
-        .. *visit::default_simple_visitor()
-    }));
+    let visit = item_stopping_visitor(
+        visit::mk_simple_visitor(@visit::SimpleVisitor {
+            visit_expr: |e: @ast::expr| {
+                match e.node {
+                    ast::expr_rec(*) =>
+                    cx.sess.span_lint(
+                        structural_records, e.id, it.id,
+                        e.span,
+                        ~"structural records are deprecated"),
+                    _ => ()
+                }
+            },
+            .. *visit::default_simple_visitor()
+        }));
     visit::visit_item(it, (), visit);
 }
 
@@ -779,34 +784,36 @@ fn check_item_heap(cx: ty::ctxt, it: @ast::item) {
       _ => ()
     }
 
-    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
-        visit_expr: fn@(e: @ast::expr) {
-            let ty = ty::expr_ty(cx, e);
-            check_type(cx, e.id, it.id, e.span, ty);
-        },
-        .. *visit::default_simple_visitor()
-    }));
+    let visit = item_stopping_visitor(
+        visit::mk_simple_visitor(@visit::SimpleVisitor {
+            visit_expr: |e: @ast::expr| {
+                let ty = ty::expr_ty(cx, e);
+                check_type(cx, e.id, it.id, e.span, ty);
+            },
+            .. *visit::default_simple_visitor()
+        }));
     visit::visit_item(it, (), visit);
 }
 
 fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) {
-    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
-        visit_stmt: fn@(s: @ast::stmt) {
-            match s.node {
-              ast::stmt_semi(@{id: id,
-                               callee_id: _,
-                               node: ast::expr_path(_),
-                               span: _}, _) => {
-                cx.sess.span_lint(
-                    path_statement, id, it.id,
-                    s.span,
-                    ~"path statement with no effect");
-              }
-              _ => ()
-            }
-        },
-        .. *visit::default_simple_visitor()
-    }));
+    let visit = item_stopping_visitor(
+        visit::mk_simple_visitor(@visit::SimpleVisitor {
+            visit_stmt: |s: @ast::stmt| {
+                match s.node {
+                    ast::stmt_semi(@{id: id,
+                                     callee_id: _,
+                                     node: ast::expr_path(_),
+                                     span: _}, _) => {
+                        cx.sess.span_lint(
+                            path_statement, id, it.id,
+                            s.span,
+                            ~"path statement with no effect");
+                    }
+                    _ => ()
+                }
+            },
+            .. *visit::default_simple_visitor()
+        }));
     visit::visit_item(it, (), visit);
 }
 
@@ -975,7 +982,7 @@ fn check_item_deprecated_modes(tcx: ty::ctxt, it: @ast::item) {
 
 fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
 
-    let v = visit::mk_simple_visitor(@{
+    let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
         visit_item: |it|
             check_item(it, tcx),
         visit_fn: |fk, decl, body, span, id|
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 6c78c270139..bfcd809594b 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -207,7 +207,7 @@ fn live_node_kind_to_str(lnk: LiveNodeKind, cx: ty::ctxt) -> ~str {
 fn check_crate(tcx: ty::ctxt,
                method_map: typeck::method_map,
                crate: @crate) -> last_use_map {
-    let visitor = visit::mk_vt(@{
+    let visitor = visit::mk_vt(@visit::Visitor {
         visit_fn: visit_fn,
         visit_local: visit_local,
         visit_expr: visit_expr,
@@ -489,7 +489,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
     let entry_ln = (*lsets).compute(decl, body);
 
     // check for various error conditions
-    let check_vt = visit::mk_vt(@{
+    let check_vt = visit::mk_vt(@visit::Visitor {
         visit_fn: check_fn,
         visit_local: check_local,
         visit_expr: check_expr,
diff --git a/src/librustc/middle/mode.rs b/src/librustc/middle/mode.rs
index 00be40cbf49..1e24ff9f5e4 100644
--- a/src/librustc/middle/mode.rs
+++ b/src/librustc/middle/mode.rs
@@ -234,7 +234,7 @@ fn compute_modes_for_pat(pat: @pat,
 }
 
 pub fn compute_modes(tcx: ctxt, method_map: method_map, crate: @crate) {
-    let visitor = visit::mk_vt(@{
+    let visitor = visit::mk_vt(@visit::Visitor {
         visit_expr: compute_modes_for_expr,
         visit_pat: compute_modes_for_pat,
         .. *visit::default_visitor()
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 56dee0843dd..745e3f6086f 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -190,7 +190,7 @@ fn check_crate(tcx: ty::ctxt, method_map: &method_map, crate: @ast::crate) {
         }
     };
 
-    let visitor = visit::mk_vt(@{
+    let visitor = visit::mk_vt(@visit::Visitor {
         visit_mod: |the_module, span, node_id, method_map, visitor| {
             let n_added = add_privileged_items(the_module.items);
 
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 21ccfd3b5f2..ae6a6d67c1d 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -352,7 +352,7 @@ fn resolve_crate(sess: Session, def_map: resolve::DefMap,
                          region_map: HashMap(),
                          root_exprs: HashMap(),
                          parent: None};
-    let visitor = visit::mk_vt(@{
+    let visitor = visit::mk_vt(@visit::Visitor {
         visit_block: resolve_block,
         visit_item: resolve_item,
         visit_fn: resolve_fn,
@@ -782,7 +782,7 @@ fn determine_rp_in_crate(sess: Session,
                                   mut ambient_variance: rv_covariant});
 
     // Gather up the base set, worklist and dep_map
-    let visitor = visit::mk_vt(@{
+    let visitor = visit::mk_vt(@visit::Visitor {
         visit_fn: determine_rp_in_fn,
         visit_item: determine_rp_in_item,
         visit_ty: determine_rp_in_ty,
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 4e5e9b97957..2fb922c3e52 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -64,7 +64,7 @@ use syntax::parse::token::ident_interner;
 use syntax::parse::token::special_idents;
 use syntax::print::pprust::{pat_to_str, path_to_str};
 use syntax::codemap::span;
-use syntax::visit::{default_visitor, fk_method, mk_vt, visit_block};
+use syntax::visit::{default_visitor, fk_method, mk_vt, Visitor, visit_block};
 use syntax::visit::{visit_crate, visit_expr, visit_expr_opt, visit_fn};
 use syntax::visit::{visit_foreign_item, visit_item, visit_method_helper};
 use syntax::visit::{visit_mod, visit_ty, vt};
@@ -947,7 +947,7 @@ impl Resolver {
     fn build_reduced_graph(this: @Resolver) {
         let initial_parent =
             ModuleReducedGraphParent((*self.graph_root).get_module());
-        visit_crate(*self.crate, initial_parent, mk_vt(@{
+        visit_crate(*self.crate, initial_parent, mk_vt(@Visitor {
             visit_item: |item, context, visitor|
                 (*this).build_reduced_graph_for_item(item, context, visitor),
 
@@ -3719,7 +3719,7 @@ impl Resolver {
     fn resolve_crate(@self) {
         debug!("(resolving crate) starting");
 
-        visit_crate(*self.crate, (), mk_vt(@{
+        visit_crate(*self.crate, (), mk_vt(@Visitor {
             visit_item: |item, _context, visitor|
                 self.resolve_item(item, visitor),
             visit_arm: |arm, _context, visitor|
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 668457a6a46..12a073e678b 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2372,10 +2372,12 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
 }
 
 fn trans_constants(ccx: @crate_ctxt, crate: @ast::crate) {
-    visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
-        visit_item: |a| trans_constant(ccx, a),
-        ..*visit::default_simple_visitor()
-    }));
+    visit::visit_crate(
+        *crate, (),
+        visit::mk_simple_visitor(@visit::SimpleVisitor {
+            visit_item: |a| trans_constant(ccx, a),
+            ..*visit::default_simple_visitor()
+        }));
 }
 
 fn vp2i(cx: block, v: ValueRef) -> ValueRef {
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index 8f02cee5b2a..d90673b31bc 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -390,7 +390,7 @@ fn trans_rtcall_or_lang_call_with_type_params(bcx: block,
 
 fn body_contains_ret(body: ast::blk) -> bool {
     let cx = {mut found: false};
-    visit::visit_block(body, cx, visit::mk_vt(@{
+    visit::visit_block(body, cx, visit::mk_vt(@visit::Visitor {
         visit_item: |_i, _cx, _v| { },
         visit_expr: |e: @ast::expr, cx: {mut found: bool}, v| {
             if !cx.found {
diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs
index 832f4f8294e..5de7ebadb2b 100644
--- a/src/librustc/middle/trans/reachable.rs
+++ b/src/librustc/middle/trans/reachable.rs
@@ -142,7 +142,8 @@ fn traverse_public_item(cx: ctx, item: @item) {
 }
 
 fn mk_ty_visitor() -> visit::vt<ctx> {
-    visit::mk_vt(@{visit_ty: traverse_ty, ..*visit::default_visitor()})
+    visit::mk_vt(@visit::Visitor {visit_ty: traverse_ty,
+                                  ..*visit::default_visitor()})
 }
 
 fn traverse_ty(ty: @Ty, cx: ctx, v: visit::vt<ctx>) {
@@ -209,7 +210,7 @@ fn traverse_inline_body(cx: ctx, body: blk) {
     fn traverse_item(i: @item, cx: ctx, _v: visit::vt<ctx>) {
       traverse_public_item(cx, i);
     }
-     visit::visit_block(body, cx, visit::mk_vt(@{
+     visit::visit_block(body, cx, visit::mk_vt(@visit::Visitor {
         visit_expr: traverse_expr,
         visit_item: traverse_item,
          ..*visit::default_visitor()
@@ -217,21 +218,23 @@ fn traverse_inline_body(cx: ctx, body: blk) {
 }
 
 fn traverse_all_resources_and_impls(cx: ctx, crate_mod: _mod) {
-    visit::visit_mod(crate_mod, ast_util::dummy_sp(), 0, cx, visit::mk_vt(@{
-        visit_expr: |_e, _cx, _v| { },
-        visit_item: |i, cx, v| {
-            visit::visit_item(i, cx, v);
-            match i.node {
-              item_struct(struct_def, _) if struct_def.dtor.is_some() => {
-                traverse_public_item(cx, i);
-              }
-              item_impl(*) => {
-                traverse_public_item(cx, i);
-              }
-              _ => ()
-            }
-        },
-        ..*visit::default_visitor()
-    }));
+    visit::visit_mod(
+        crate_mod, ast_util::dummy_sp(), 0, cx,
+        visit::mk_vt(@visit::Visitor {
+            visit_expr: |_e, _cx, _v| { },
+            visit_item: |i, cx, v| {
+                visit::visit_item(i, cx, v);
+                match i.node {
+                    item_struct(sdef, _) if sdef.dtor.is_some() => {
+                        traverse_public_item(cx, i);
+                    }
+                    item_impl(*) => {
+                        traverse_public_item(cx, i);
+                    }
+                    _ => ()
+                }
+            },
+            ..*visit::default_visitor()
+        }));
 }
 
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
index 1b2fc4e387a..e17a9c8c0ed 100644
--- a/src/librustc/middle/trans/type_use.rs
+++ b/src/librustc/middle/trans/type_use.rs
@@ -340,7 +340,7 @@ fn mark_for_expr(cx: ctx, e: @expr) {
 }
 
 fn handle_body(cx: ctx, body: blk) {
-    let v = visit::mk_vt(@{
+    let v = visit::mk_vt(@visit::Visitor {
         visit_expr: |e, cx, v| {
             visit::visit_expr(e, cx, v);
             mark_for_expr(cx, e);
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 65533571f9a..d29858e1fa4 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -47,7 +47,7 @@ use syntax::ast::*;
 use syntax::ast_util::{is_local, local_def};
 use syntax::ast_util;
 use syntax::codemap::span;
-use syntax::print::pprust::*;
+use syntax::print::pprust;
 use syntax::{ast, ast_map};
 use syntax;
 
@@ -55,7 +55,7 @@ export ProvidedMethodSource;
 export ProvidedMethodInfo;
 export ProvidedMethodsMap;
 export InstantiatedTraitRef;
-export TyVid, IntVid, FloatVid, FnVid, RegionVid, vid;
+export TyVid, IntVid, FloatVid, FnVid, RegionVid, Vid;
 export br_hashmap;
 export is_instantiable;
 export node_id_to_type;
@@ -118,7 +118,8 @@ export ty_opaque_closure_ptr, mk_opaque_closure_ptr;
 export ty_opaque_box, mk_opaque_box;
 export ty_float, mk_float, mk_mach_float, type_is_fp;
 export ty_fn, FnTy, FnTyBase, FnMeta, FnSig, mk_fn;
-export ty_fn_proto, ty_fn_purity, ty_fn_ret, tys_in_fn_ty;
+export ty_fn_proto, ty_fn_purity, ty_fn_ret, tys_in_fn_sig;
+export replace_fn_return_type;
 export ty_int, mk_int, mk_mach_int, mk_char;
 export mk_i8, mk_u8, mk_i16, mk_u16, mk_i32, mk_u32, mk_i64, mk_u64;
 export mk_f32, mk_f64;
@@ -139,7 +140,8 @@ export ty_tup, mk_tup;
 export ty_type, mk_type;
 export ty_uint, mk_uint, mk_mach_uint;
 export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box;
-export ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var, mk_float_var;
+export ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var;
+export mk_float_var;
 export InferTy, TyVar, IntVar, FloatVar;
 export ValueMode, ReadValue, CopyValue, MoveValue;
 export ty_self, mk_self, type_has_self;
@@ -222,7 +224,6 @@ export terr_regions_insufficiently_polymorphic;
 export terr_regions_overly_polymorphic;
 export terr_proto_mismatch;
 export terr_fn, terr_trait;
-export purity_to_str;
 export onceness_to_str;
 export param_tys_in_type;
 export eval_repeat_count;
@@ -519,6 +520,7 @@ pure fn type_id(t: t) -> uint { get(t).id }
  *   times.
  * - `region` is the region bound on the function's upvars (often &static).
  * - `bounds` is the parameter bounds on the function's upvars. */
+#[deriving_eq]
 struct FnMeta {
     purity: ast::purity,
     proto: ast::Proto,
@@ -533,6 +535,7 @@ struct FnMeta {
  *
  * - `inputs` is the list of arguments and their modes.
  * - `output` is the return type. */
+#[deriving_eq]
 struct FnSig {
     inputs: ~[arg],
     output: t
@@ -543,9 +546,16 @@ struct FnSig {
  * type signature.  This particular type is parameterized
  * by the meta information because, in some cases, the
  * meta information is inferred. */
+#[deriving_eq]
 struct FnTyBase<M: cmp::Eq> {
-    meta: M,
-    sig: FnSig
+    meta: M,        // Either FnMeta or FnVid
+    sig: FnSig      // Types of arguments/return type
+}
+
+impl<M: to_bytes::IterBytes> FnTyBase<M> : to_bytes::IterBytes {
+    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
+        to_bytes::iter_bytes_2(&self.meta, &self.sig, lsb0, f)
+    }
 }
 
 type FnTy = FnTyBase<FnMeta>;
@@ -673,7 +683,7 @@ enum sty {
     ty_param(param_ty), // type parameter
     ty_self, // special, implicit `self` type parameter
 
-    ty_infer(InferTy), // soething used only during inference/typeck
+    ty_infer(InferTy), // something used only during inference/typeck
     ty_err, // Also only used during inference/typeck, to represent
             // the type of an erroneous expression (helps cut down
             // on non-useful type error messages)
@@ -742,6 +752,7 @@ enum FnVid = uint;
 #[auto_decode]
 enum RegionVid = uint;
 
+#[deriving_eq]
 enum InferTy {
     TyVar(TyVid),
     IntVar(IntVid),
@@ -753,7 +764,7 @@ impl InferTy : to_bytes::IterBytes {
         match *self {
           TyVar(ref tv) => to_bytes::iter_bytes_2(&0u8, tv, lsb0, f),
           IntVar(ref iv) => to_bytes::iter_bytes_2(&1u8, iv, lsb0, f),
-          FloatVar(ref fv) => to_bytes::iter_bytes_2(&2u8, fv, lsb0, f)
+          FloatVar(ref fv) => to_bytes::iter_bytes_2(&2u8, fv, lsb0, f),
         }
     }
 }
@@ -804,61 +815,64 @@ impl param_bound : to_bytes::IterBytes {
     }
 }
 
-trait vid {
+trait Vid {
     pure fn to_uint() -> uint;
-    pure fn to_str() -> ~str;
 }
 
-impl TyVid: vid {
+impl TyVid: Vid {
     pure fn to_uint() -> uint { *self }
+}
+
+impl TyVid: ToStr {
     pure fn to_str() -> ~str { fmt!("<V%u>", self.to_uint()) }
 }
 
-impl IntVid: vid {
+impl IntVid: Vid {
     pure fn to_uint() -> uint { *self }
+}
+
+impl IntVid: ToStr {
     pure fn to_str() -> ~str { fmt!("<VI%u>", self.to_uint()) }
 }
 
-impl FloatVid: vid {
+impl FloatVid: Vid {
     pure fn to_uint() -> uint { *self }
+}
+
+impl FloatVid: ToStr {
     pure fn to_str() -> ~str { fmt!("<VF%u>", self.to_uint()) }
 }
 
-impl FnVid: vid {
+impl FnVid: Vid {
     pure fn to_uint() -> uint { *self }
+}
+
+impl FnVid: ToStr {
     pure fn to_str() -> ~str { fmt!("<F%u>", self.to_uint()) }
 }
 
-impl RegionVid: vid {
+impl RegionVid: Vid {
     pure fn to_uint() -> uint { *self }
-    pure fn to_str() -> ~str { fmt!("%?", self) }
 }
 
-impl InferTy {
-    pure fn to_hash() -> uint {
-        match self {
-            TyVar(v) => v.to_uint() << 1,
-            IntVar(v) => (v.to_uint() << 1) + 1,
-            FloatVar(v) => (v.to_uint() << 1) + 2
-        }
-    }
+impl RegionVid: ToStr {
+    pure fn to_str() -> ~str { fmt!("%?", self) }
+}
 
+impl FnSig : ToStr {
     pure fn to_str() -> ~str {
-        match self {
-            TyVar(v) => v.to_str(),
-            IntVar(v) => v.to_str(),
-            FloatVar(v) => v.to_str()
-        }
+        // grr, without tcx not much we can do.
+        return ~"(...)";
     }
 }
 
-trait purity_to_str {
-    pure fn to_str() -> ~str;
-}
-
-impl purity: purity_to_str {
+impl InferTy: ToStr {
     pure fn to_str() -> ~str {
-        purity_to_str(self)
+        match self {
+            TyVar(ref v) => v.to_str(),
+            IntVar(ref v) => v.to_str(),
+            FloatVar(ref v) => v.to_str()
+        }
     }
 }
 
@@ -1197,7 +1211,7 @@ fn mk_int_var(cx: ctxt, v: IntVid) -> t { mk_infer(cx, IntVar(v)) }
 
 fn mk_float_var(cx: ctxt, v: FloatVid) -> t { mk_infer(cx, FloatVar(v)) }
 
-fn mk_infer(cx: ctxt, it: InferTy) -> t { mk_t(cx, ty_infer(it)) }
+fn mk_infer(cx: ctxt, +it: InferTy) -> t { mk_t(cx, ty_infer(it)) }
 
 fn mk_self(cx: ctxt) -> t { mk_t(cx, ty_self) }
 
@@ -1369,15 +1383,8 @@ fn fold_sty(sty: &sty, fldop: fn(t) -> t) -> sty {
             ty_tup(new_ts)
         }
         ty_fn(ref f) => {
-            let new_args = f.sig.inputs.map(|a| {
-                let new_ty = fldop(a.ty);
-                {mode: a.mode, ty: new_ty}
-            });
-            let new_output = fldop(f.sig.output);
-            ty_fn(FnTyBase {
-                meta: f.meta,
-                sig: FnSig {inputs: new_args, output: new_output}
-            })
+            let sig = fold_sig(&f.sig, fldop);
+            ty_fn(FnTyBase {meta: f.meta, sig: sig})
         }
         ty_rptr(r, tm) => {
             ty_rptr(r, {ty: fldop(tm.ty), mutbl: tm.mutbl})
@@ -1424,8 +1431,8 @@ fn fold_regions_and_ty(
     fn fold_substs(
         substs: &substs,
         fldr: fn(r: Region) -> Region,
-        fldt: fn(t: t) -> t) -> substs {
-
+        fldt: fn(t: t) -> t) -> substs
+    {
         {self_r: substs.self_r.map(|r| fldr(*r)),
          self_ty: substs.self_ty.map(|t| fldt(*t)),
          tps: substs.tps.map(|t| fldt(*t))}
@@ -1457,18 +1464,9 @@ fn fold_regions_and_ty(
         ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), vst)
       }
       ty_fn(ref f) => {
-          let new_region = fldr(f.meta.region);
-          let new_args = vec::map(f.sig.inputs, |a| {
-              let new_ty = fldfnt(a.ty);
-              {mode: a.mode, ty: new_ty}
-          });
-          let new_output = fldfnt(f.sig.output);
-          ty::mk_fn(cx, FnTyBase {
-              meta: FnMeta {region: new_region,
-                            ..f.meta},
-              sig: FnSig {inputs: new_args,
-                          output: new_output}
-          })
+          ty::mk_fn(cx, FnTyBase {meta: FnMeta {region: fldr(f.meta.region),
+                                                ..f.meta},
+                                  sig: fold_sig(&f.sig, fldfnt)})
       }
       ref sty => {
         fold_sty_to_ty(cx, sty, |t| fldt(t))
@@ -1509,6 +1507,7 @@ fn fold_regions(
 {
     fn do_fold(cx: ctxt, ty: t, in_fn: bool,
                fldr: fn(Region, bool) -> Region) -> t {
+        debug!("do_fold(ty=%s, in_fn=%b)", ty_to_str(cx, ty), in_fn);
         if !type_has_regions(ty) { return ty; }
         fold_regions_and_ty(
             cx, ty,
@@ -2834,8 +2833,9 @@ impl arg : to_bytes::IterBytes {
 
 impl FnMeta : to_bytes::IterBytes {
     pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
-        to_bytes::iter_bytes_4(&self.purity,
+        to_bytes::iter_bytes_5(&self.purity,
                                &self.proto,
+                               &self.onceness,
                                &self.region,
                                &self.bounds,
                                lsb0, f);
@@ -2887,10 +2887,7 @@ impl sty : to_bytes::IterBytes {
           to_bytes::iter_bytes_2(&11u8, fs, lsb0, f),
 
           ty_fn(ref ft) =>
-          to_bytes::iter_bytes_3(&12u8,
-                                 &ft.meta,
-                                 &ft.sig,
-                                 lsb0, f),
+          to_bytes::iter_bytes_2(&12u8, ft, lsb0, f),
 
           ty_self => 13u8.iter_bytes(lsb0, f),
 
@@ -2978,8 +2975,8 @@ fn ty_fn_purity(fty: t) -> ast::purity {
 
 pure fn ty_fn_ret(fty: t) -> t {
     match get(fty).sty {
-      ty_fn(ref f) => f.sig.output,
-      _ => fail ~"ty_fn_ret() called on non-fn type"
+        ty_fn(ref f) => f.sig.output,
+        _ => fail ~"ty_fn_ret() called on non-fn type"
     }
 }
 
@@ -2997,9 +2994,30 @@ fn ty_region(ty: t) -> Region {
     }
 }
 
+fn replace_fn_return_type(tcx: ctxt, fn_type: t, ret_type: t) -> t {
+    /*!
+     *
+     * Returns a new function type based on `fn_type` but returning a value of
+     * type `ret_type` instead. */
+
+    match ty::get(fn_type).sty {
+        ty::ty_fn(ref fty) => {
+            ty::mk_fn(tcx, FnTyBase {
+                meta: fty.meta,
+                sig: FnSig {output: ret_type, ..copy fty.sig}
+            })
+        }
+        _ => {
+            tcx.sess.bug(fmt!(
+                "replace_fn_ret() invoked with non-fn-type: %s",
+                ty_to_str(tcx, fn_type)));
+        }
+    }
+}
+
 // Returns a vec of all the input and output types of fty.
-fn tys_in_fn_ty(fty: &FnTy) -> ~[t] {
-    vec::append_one(fty.sig.inputs.map(|a| a.ty), fty.sig.output)
+fn tys_in_fn_sig(sig: &FnSig) -> ~[t] {
+    vec::append_one(sig.inputs.map(|a| a.ty), sig.output)
 }
 
 // Just checks whether it's a fn that returns bool,
@@ -3444,18 +3462,16 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
         terr_mismatch => ~"types differ",
         terr_purity_mismatch(values) => {
             fmt!("expected %s fn but found %s fn",
-                 purity_to_str(values.expected),
-                 purity_to_str(values.found))
+                 values.expected.to_str(), values.found.to_str())
         }
         terr_onceness_mismatch(values) => {
             fmt!("expected %s fn but found %s fn",
-                 onceness_to_str(values.expected),
-                 onceness_to_str(values.found))
+                 values.expected.to_str(), values.found.to_str())
         }
         terr_proto_mismatch(values) => {
             fmt!("expected %s closure, found %s closure",
-                 proto_ty_to_str(cx, values.expected),
-                 proto_ty_to_str(cx, values.found))
+                 proto_ty_to_str(cx, values.expected, false),
+                 proto_ty_to_str(cx, values.found, false))
         }
         terr_mutability => ~"values differ in mutability",
         terr_box_mutability => ~"boxed values differ in mutability",
@@ -3489,7 +3505,8 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
         terr_arg_count => ~"incorrect number of function parameters",
         terr_mode_mismatch(values) => {
             fmt!("expected argument mode %s, but found %s",
-                 mode_to_str(values.expected), mode_to_str(values.found))
+                 pprust::mode_to_str(values.expected),
+                 pprust::mode_to_str(values.found))
         }
         terr_regions_does_not_outlive(*) => {
             fmt!("lifetime mismatch")
@@ -4398,30 +4415,6 @@ impl vstore : cmp::Eq {
     pure fn ne(&self, other: &vstore) -> bool { !(*self).eq(other) }
 }
 
-impl FnMeta : cmp::Eq {
-    pure fn eq(&self, other: &FnMeta) -> bool {
-        (*self).purity == (*other).purity &&
-        (*self).proto == (*other).proto &&
-        (*self).bounds == (*other).bounds
-    }
-    pure fn ne(&self, other: &FnMeta) -> bool { !(*self).eq(other) }
-}
-
-impl FnSig : cmp::Eq {
-    pure fn eq(&self, other: &FnSig) -> bool {
-        (*self).inputs == (*other).inputs &&
-        (*self).output == (*other).output
-    }
-    pure fn ne(&self, other: &FnSig) -> bool { !(*self).eq(other) }
-}
-
-impl<M: cmp::Eq> FnTyBase<M> : cmp::Eq {
-    pure fn eq(&self, other: &FnTyBase<M>) -> bool {
-        (*self).meta == (*other).meta && (*self).sig == (*other).sig
-    }
-    pure fn ne(&self, other: &FnTyBase<M>) -> bool { !(*self).eq(other) }
-}
-
 impl TyVid : cmp::Eq {
     pure fn eq(&self, other: &TyVid) -> bool { *(*self) == *(*other) }
     pure fn ne(&self, other: &TyVid) -> bool { *(*self) != *(*other) }
@@ -4532,13 +4525,6 @@ impl substs : cmp::Eq {
     pure fn ne(&self, other: &substs) -> bool { !(*self).eq(other) }
 }
 
-impl InferTy : cmp::Eq {
-    pure fn eq(&self, other: &InferTy) -> bool {
-        (*self).to_hash() == (*other).to_hash()
-    }
-    pure fn ne(&self, other: &InferTy) -> bool { !(*self).eq(other) }
-}
-
 impl sty : cmp::Eq {
     pure fn eq(&self, other: &sty) -> bool {
         match (/*bad*/copy *self) {
@@ -4651,9 +4637,9 @@ impl sty : cmp::Eq {
                     _ => false
                 }
             }
-            ty_infer(e0a) => {
+            ty_infer(ref e0a) => {
                 match (*other) {
-                    ty_infer(e0b) => e0a == e0b,
+                    ty_infer(ref e0b) => *e0a == *e0b,
                     _ => false
                 }
             }
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index a8c1b0aaa90..05061ccfa13 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -1137,7 +1137,7 @@ impl LookupContext {
                  ty::item_path_str(self.tcx(), did)));
     }
 
-    fn infcx(&self) -> infer::infer_ctxt {
+    fn infcx(&self) -> @infer::InferCtxt {
         self.fcx.inh.infcx
     }
 
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 69b2724c054..ff99ee8590a 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -82,8 +82,9 @@ use middle::capture;
 use middle::const_eval;
 use middle::pat_util::pat_id_map;
 use middle::pat_util;
-use middle::ty::{TyVid, vid, FnTyBase, FnMeta, FnSig, VariantInfo_, field};
+use middle::ty::{TyVid, Vid, FnTyBase, FnMeta, FnSig, VariantInfo_, field};
 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
+use middle::ty::{re_bound, br_cap_avoid};
 use middle::ty;
 use middle::typeck::astconv::{ast_conv, ast_path_to_ty};
 use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
@@ -91,6 +92,7 @@ use middle::typeck::astconv;
 use middle::typeck::check::_match::pat_ctxt;
 use middle::typeck::check::method::TransformTypeNormally;
 use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_ty;
+use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
 use middle::typeck::check::vtable::{LocationInfo, VtableContext};
 use middle::typeck::crate_ctxt;
 use middle::typeck::infer::{resolve_type, force_tvar};
@@ -187,7 +189,7 @@ type self_info = {
 /// `bar()` will each have their own `fn_ctxt`, but they will
 /// share the inherited fields.
 struct inherited {
-    infcx: infer::infer_ctxt,
+    infcx: @infer::InferCtxt,
     locals: HashMap<ast::node_id, TyVid>,
     node_types: HashMap<ast::node_id, ty::t>,
     node_type_substs: HashMap<ast::node_id, ty::substs>,
@@ -265,7 +267,7 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
 }
 
 fn check_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
-    let visit = visit::mk_simple_visitor(@{
+    let visit = visit::mk_simple_visitor(@visit::SimpleVisitor {
         visit_item: |a| check_item(ccx, a),
         .. *visit::default_simple_visitor()
     });
@@ -273,7 +275,7 @@ fn check_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
 }
 
 fn check_bare_fn(ccx: @crate_ctxt,
-                 decl: ast::fn_decl,
+                 decl: &ast::fn_decl,
                  body: ast::blk,
                  id: ast::node_id,
                  self_info: Option<self_info>) {
@@ -290,7 +292,7 @@ fn check_bare_fn(ccx: @crate_ctxt,
 fn check_fn(ccx: @crate_ctxt,
             self_info: Option<self_info>,
             fn_ty: &ty::FnTy,
-            decl: ast::fn_decl,
+            decl: &ast::fn_decl,
             body: ast::blk,
             fn_kind: FnKind,
             old_fcx: Option<@fn_ctxt>) {
@@ -305,15 +307,15 @@ fn check_fn(ccx: @crate_ctxt,
     // types with free ones.  The free region references will be bound
     // the node_id of the body block.
 
-    let {isr: isr, self_info: self_info, fn_ty: fn_ty} = {
+    let {isr, self_info, fn_sig} = {
         let old_isr = option::map_default(&old_fcx, @Nil,
-                                         |fcx| fcx.in_scope_regions);
-        replace_bound_regions_in_fn_ty(tcx, old_isr, self_info, fn_ty,
-                                       |br| ty::re_free(body.node.id, br))
+                                          |fcx| fcx.in_scope_regions);
+        replace_bound_regions_in_fn_sig(tcx, old_isr, self_info, &fn_ty.sig,
+                                        |br| ty::re_free(body.node.id, br))
     };
 
-    let arg_tys = fn_ty.sig.inputs.map(|a| a.ty);
-    let ret_ty = fn_ty.sig.output;
+    let arg_tys = fn_sig.inputs.map(|a| a.ty);
+    let ret_ty = fn_sig.output;
 
     debug!("check_fn(arg_tys=%?, ret_ty=%?, self_info.self_ty=%?)",
            arg_tys.map(|a| ppaux::ty_to_str(tcx, *a)),
@@ -406,12 +408,12 @@ fn check_fn(ccx: @crate_ctxt,
     // resolved when the enclosing scope finishes up.
     if old_fcx.is_none() {
         vtable::resolve_in_block(fcx, body);
-        regionck::regionck_fn(fcx, decl, body);
+        regionck::regionck_fn(fcx, body);
         writeback::resolve_type_vars_in_fn(fcx, decl, body, self_info);
     }
 
     fn gather_locals(fcx: @fn_ctxt,
-                     decl: ast::fn_decl,
+                     decl: &ast::fn_decl,
                      body: ast::blk,
                      arg_tys: ~[ty::t],
                      self_info: Option<self_info>) {
@@ -503,12 +505,13 @@ fn check_fn(ccx: @crate_ctxt,
         }
         fn visit_item(_i: @ast::item, &&_e: (), _v: visit::vt<()>) { }
 
-        let visit = visit::mk_vt(@{visit_local: visit_local,
-                                   visit_pat: visit_pat,
-                                   visit_fn: visit_fn,
-                                   visit_item: visit_item,
-                                   visit_block: visit_block,
-                                   .. *visit::default_visitor()});
+        let visit = visit::mk_vt(
+            @visit::Visitor {visit_local: visit_local,
+                             visit_pat: visit_pat,
+                             visit_fn: visit_fn,
+                             visit_item: visit_item,
+                             visit_block: visit_block,
+                             ..*visit::default_visitor()});
 
         (visit.visit_block)(body, (), visit);
     }
@@ -520,7 +523,7 @@ fn check_method(ccx: @crate_ctxt, method: @ast::method,
                      self_id: method.self_id,
                      def_id: self_impl_def_id,
                      explicit_self: method.self_ty };
-    check_bare_fn(ccx, method.decl, method.body, method.id, Some(self_info));
+    check_bare_fn(ccx, &method.decl, method.body, method.id, Some(self_info));
 }
 
 fn check_no_duplicate_fields(tcx: ty::ctxt, fields:
@@ -559,7 +562,8 @@ fn check_struct(ccx: @crate_ctxt, struct_def: @ast::struct_def,
                             spanned { node: ast::sty_by_ref,
                                       span: ast_util::dummy_sp() } };
         // typecheck the dtor
-        check_bare_fn(ccx, ast_util::dtor_dec(),
+        let dtor_dec = ast_util::dtor_dec();
+        check_bare_fn(ccx, &dtor_dec,
                       dtor.node.body, dtor.node.id,
                       Some(class_t));
     };
@@ -583,7 +587,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
                             it.id);
       }
       ast::item_fn(ref decl, _, _, ref body) => {
-        check_bare_fn(ccx, *decl, (*body), it.id, None);
+        check_bare_fn(ccx, decl, (*body), it.id, None);
       }
       ast::item_impl(_, _, ty, ms) => {
         let rp = ccx.tcx.region_paramd_items.find(it.id);
@@ -657,7 +661,7 @@ impl @fn_ctxt: ast_conv {
 }
 
 impl @fn_ctxt {
-    fn infcx() -> infer::infer_ctxt { self.inh.infcx }
+    fn infcx() -> @infer::InferCtxt { self.inh.infcx }
     fn search_in_scope_regions(br: ty::bound_region)
         -> Result<ty::Region, ~str>
     {
@@ -1519,7 +1523,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
     fn check_expr_fn(fcx: @fn_ctxt,
                      expr: @ast::expr,
                      ast_proto_opt: Option<ast::Proto>,
-                     decl: ast::fn_decl,
+                     decl: &ast::fn_decl,
                      body: ast::blk,
                      fn_kind: FnKind,
                      expected: Option<ty::t>) {
@@ -1569,7 +1573,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
             fcx, fcx,
             proto, purity, expected_onceness,
             /*bounds:*/ @~[], /*opt_region:*/ None,
-            decl, expected_tys, expr.span);
+            *decl, expected_tys, expr.span);
 
         // XXX: Bad copy.
         let fty = ty::mk_fn(tcx, copy fn_ty);
@@ -2157,12 +2161,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
       }
       ast::expr_fn(proto, ref decl, ref body, cap_clause) => {
         check_expr_fn(fcx, expr, Some(proto),
-                      *decl, (*body), Vanilla, expected);
+                      decl, (*body), Vanilla, expected);
         capture::check_capture_clause(tcx, expr.id, cap_clause);
       }
       ast::expr_fn_block(ref decl, ref body, cap_clause) => {
         check_expr_fn(fcx, expr, None,
-                      *decl, (*body), Vanilla, expected);
+                      decl, (*body), Vanilla, expected);
         capture::check_capture_clause(tcx, expr.id, cap_clause);
       }
       ast::expr_loop_body(b) => {
@@ -2218,7 +2222,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         match b.node {
           ast::expr_fn_block(ref decl, ref body, cap_clause) => {
             check_expr_fn(fcx, b, None,
-                          *decl, (*body), ForLoop, Some(inner_ty));
+                          decl, *body, ForLoop, Some(inner_ty));
             demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
             capture::check_capture_clause(tcx, b.id, cap_clause);
           }
@@ -2227,20 +2231,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         }
         let block_ty = structurally_resolved_type(
             fcx, expr.span, fcx.node_ty(b.id));
-        match ty::get(block_ty).sty {
-          ty::ty_fn(ref fty) => {
-              if !err_happened {
-                  fcx.write_ty(expr.id, ty::mk_fn(tcx, FnTyBase {
-                      meta: (*fty).meta,
-                      sig: FnSig {output: ty::mk_bool(tcx),
-                                  ../*bad*/copy (*fty).sig}
-                  }));
-              }
-              else {
-                  fcx.write_ty(expr.id, ty::mk_err(fcx.tcx()));
-              }
-          }
-          _ => fail ~"expected fn type"
+        if err_happened {
+            fcx.write_ty(expr.id, ty::mk_err(fcx.tcx()));
+        } else {
+            let loop_body_ty = ty::replace_fn_return_type(tcx, block_ty,
+                                                          ty::mk_bool(tcx));
+            fcx.write_ty(expr.id, loop_body_ty);
         }
       }
       ast::expr_do_body(b) => {
@@ -2267,21 +2263,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         match b.node {
           ast::expr_fn_block(ref decl, ref body, cap_clause) => {
             check_expr_fn(fcx, b, None,
-                          *decl, (*body), DoBlock, Some(inner_ty));
+                          decl, *body, DoBlock, Some(inner_ty));
             demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
             capture::check_capture_clause(tcx, b.id, cap_clause);
           }
           // argh
           _ => fail ~"expected fn ty"
         }
-        let block_ty = structurally_resolved_type(
-            fcx, expr.span, fcx.node_ty(b.id));
-        match ty::get(block_ty).sty {
-          ty::ty_fn(ref fty) => {
-            fcx.write_ty(expr.id, ty::mk_fn(tcx, (/*bad*/copy *fty)));
-          }
-          _ => fail ~"expected fn ty"
-        }
+        fcx.write_ty(expr.id, fcx.node_ty(b.id));
       }
       ast::expr_block(ref b) => {
         // If this is an unchecked block, turn off purity-checking
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 029a61c8ca6..3901752ac68 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -114,7 +114,6 @@ fn regionck_expr(fcx: @fn_ctxt, e: @ast::expr) {
 }
 
 fn regionck_fn(fcx: @fn_ctxt,
-               _decl: ast::fn_decl,
                blk: ast::blk) {
     let rcx = rcx_({fcx:fcx, mut errors_reported: 0});
     let v = regionck_visitor();
@@ -123,12 +122,12 @@ fn regionck_fn(fcx: @fn_ctxt,
 }
 
 fn regionck_visitor() -> rvt {
-    visit::mk_vt(@{visit_item: visit_item,
-                   visit_stmt: visit_stmt,
-                   visit_expr: visit_expr,
-                   visit_block: visit_block,
-                   visit_local: visit_local,
-                   .. *visit::default_visitor()})
+    visit::mk_vt(@visit::Visitor {visit_item: visit_item,
+                                  visit_stmt: visit_stmt,
+                                  visit_expr: visit_expr,
+                                  visit_block: visit_block,
+                                  visit_local: visit_local,
+                                  .. *visit::default_visitor()})
 }
 
 fn visit_item(_item: @ast::item, &&_rcx: @rcx, _v: rvt) {
diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs
index 1e4082fc961..8097b0eca84 100644
--- a/src/librustc/middle/typeck/check/regionmanip.rs
+++ b/src/librustc/middle/typeck/check/regionmanip.rs
@@ -12,6 +12,7 @@
 
 use core::prelude::*;
 
+use middle::ty::{FnTyBase};
 use middle::ty;
 use middle::typeck::check::self_info;
 use middle::typeck::isr_alist;
@@ -25,22 +26,37 @@ use syntax::print::pprust::{expr_to_str};
 
 // Helper functions related to manipulating region types.
 
-fn replace_bound_regions_in_fn_ty(
+pub fn replace_bound_regions_in_fn_ty(
     tcx: ty::ctxt,
     isr: isr_alist,
     self_info: Option<self_info>,
     fn_ty: &ty::FnTy,
     mapf: fn(ty::bound_region) -> ty::Region) ->
-    {isr: isr_alist, self_info: Option<self_info>, fn_ty: ty::FnTy} {
+    {isr: isr_alist, self_info: Option<self_info>, fn_ty: ty::FnTy}
+{
+    let {isr, self_info, fn_sig} =
+        replace_bound_regions_in_fn_sig(
+            tcx, isr, self_info, &fn_ty.sig, mapf);
+    {isr: isr,
+     self_info: self_info,
+     fn_ty: FnTyBase {meta: fn_ty.meta,
+                      sig: fn_sig}}
+}
 
+pub fn replace_bound_regions_in_fn_sig(
+    tcx: ty::ctxt,
+    isr: isr_alist,
+    self_info: Option<self_info>,
+    fn_sig: &ty::FnSig,
+    mapf: fn(ty::bound_region) -> ty::Region) ->
+    {isr: isr_alist, self_info: Option<self_info>, fn_sig: ty::FnSig}
+{
     // Take self_info apart; the self_ty part is the only one we want
     // to update here.
-    let (self_ty, rebuild_self_info) = match self_info {
-      Some(copy s) => (Some(s.self_ty), |t| Some({self_ty: t,.. s})),
-      None => (None, |_t| None)
-    };
+    let self_ty = self_info.map(|s| s.self_ty);
+    let rebuild_self_info = |t| self_info.map(|s| {self_ty: t, ..*s});
 
-    let mut all_tys = ty::tys_in_fn_ty(fn_ty);
+    let mut all_tys = ty::tys_in_fn_sig(fn_sig);
 
     match self_info {
       Some({explicit_self: ast::spanned { node: ast::sty_region(m),
@@ -56,10 +72,10 @@ fn replace_bound_regions_in_fn_ty(
 
     for self_ty.each |t| { all_tys.push(*t) }
 
-    debug!("replace_bound_regions_in_fn_ty(self_info.self_ty=%?, fn_ty=%s, \
-                all_tys=%?)",
+    debug!("replace_bound_regions_in_fn_sig(self_info.self_ty=%?, fn_sig=%s, \
+            all_tys=%?)",
            self_ty.map(|t| ppaux::ty_to_str(tcx, *t)),
-           ppaux::ty_to_str(tcx, ty::mk_fn(tcx, *fn_ty)),
+           ppaux::fn_sig_to_str(tcx, fn_sig),
            all_tys.map(|t| ppaux::ty_to_str(tcx, *t)));
     let _i = indenter();
 
@@ -67,17 +83,15 @@ fn replace_bound_regions_in_fn_ty(
         debug!("br=%?", br);
         mapf(br)
     };
-    let ty_fn = ty::ty_fn(/*bad*/copy *fn_ty);
-    let t_fn = ty::fold_sty_to_ty(tcx, &ty_fn, |t| {
+    let new_fn_sig = ty::fold_sig(fn_sig, |t| {
         replace_bound_regions(tcx, isr, t)
     });
     let t_self = self_ty.map(|t| replace_bound_regions(tcx, isr, *t));
 
-    debug!("result of replace_bound_regions_in_fn_ty: self_info.self_ty=%?, \
-                fn_ty=%s",
+    debug!("result of replace_bound_regions_in_fn_sig: self_info.self_ty=%?, \
+                fn_sig=%s",
            t_self.map(|t| ppaux::ty_to_str(tcx, *t)),
-           ppaux::ty_to_str(tcx, t_fn));
-
+           ppaux::fn_sig_to_str(tcx, &new_fn_sig));
 
     // Glue updated self_ty back together with its original def_id.
     let new_self_info: Option<self_info> = match t_self {
@@ -86,10 +100,8 @@ fn replace_bound_regions_in_fn_ty(
     };
 
     return {isr: isr,
-         self_info: new_self_info,
-         fn_ty: match ty::get(t_fn).sty { ty::ty_fn(ref o) => /*bad*/copy *o,
-          _ => tcx.sess.bug(~"replace_bound_regions_in_fn_ty: impossible")}};
-
+            self_info: new_self_info,
+            fn_sig: new_fn_sig};
 
     // Takes `isr`, a (possibly empty) mapping from in-scope region
     // names ("isr"s) to their corresponding regions; `tys`, a list of
@@ -158,7 +170,7 @@ fn replace_bound_regions_in_fn_ty(
         ty: ty::t) -> ty::t {
 
         do ty::fold_regions(tcx, ty) |r, in_fn| {
-            match r {
+            let r1 = match r {
               // As long as we are not within a fn() type, `&T` is
               // mapped to the free region anon_r.  But within a fn
               // type, it remains bound.
@@ -187,7 +199,8 @@ fn replace_bound_regions_in_fn_ty(
               ty::re_scope(_) |
               ty::re_free(_, _) |
               ty::re_infer(_) => r
-            }
+            };
+            r1
         }
     }
 }
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 593d32c644e..9d309d4996b 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -14,7 +14,7 @@ use middle::resolve;
 use middle::ty;
 use middle::typeck::check::{fn_ctxt, impl_self_ty};
 use middle::typeck::check::{structurally_resolved_type};
-use middle::typeck::infer::{fixup_err_to_str, infer_ctxt};
+use middle::typeck::infer::{fixup_err_to_str, InferCtxt};
 use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
 use middle::typeck::infer;
 use middle::typeck::{crate_ctxt, vtable_origin, vtable_param, vtable_res};
@@ -63,7 +63,7 @@ struct LocationInfo {
 /// callback function to call in case of type error.
 struct VtableContext {
     ccx: @crate_ctxt,
-    infcx: infer::infer_ctxt
+    infcx: @infer::InferCtxt
 }
 
 impl VtableContext {
@@ -685,8 +685,8 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
                             ex.span,
                             fmt!("failed to find an implementation of trait \
                                   %s for %s",
-                                 ppaux::ty_to_str(fcx.tcx(), target_ty),
-                                 ppaux::ty_to_str(fcx.tcx(), ty)));
+                                 fcx.infcx().ty_to_str(target_ty),
+                                 fcx.infcx().ty_to_str(ty)));
                     }
                 }
                 Some(vtable) => {
@@ -714,7 +714,7 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
 // Detect points where a trait-bounded type parameter is
 // instantiated, resolve the impls for the parameters.
 fn resolve_in_block(fcx: @fn_ctxt, bl: ast::blk) {
-    visit::visit_block(bl, fcx, visit::mk_vt(@{
+    visit::visit_block(bl, fcx, visit::mk_vt(@visit::Visitor {
         visit_expr: resolve_expr,
         visit_item: fn@(_i: @ast::item, &&_e: @fn_ctxt,
                         _v: visit::vt<@fn_ctxt>) {},
diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs
index a00fe073c54..b00a3306ceb 100644
--- a/src/librustc/middle/typeck/check/writeback.rs
+++ b/src/librustc/middle/typeck/check/writeback.rs
@@ -161,9 +161,8 @@ fn visit_expr(e: @ast::expr, wbcx: wb_ctxt, v: wb_vt) {
     resolve_type_vars_for_node(wbcx, e.span, e.id);
     resolve_method_map_entry(wbcx.fcx, e.span, e.id);
     resolve_method_map_entry(wbcx.fcx, e.span, e.callee_id);
-    match /*bad*/copy e.node {
-      ast::expr_fn(_, decl, _, _) |
-      ast::expr_fn_block(decl, _, _) => {
+    match e.node {
+      ast::expr_fn_block(ref decl, _, _) => {
           for vec::each(decl.inputs) |input| {
               let r_ty = resolve_type_vars_for_node(wbcx, e.span, input.id);
 
@@ -237,13 +236,13 @@ fn visit_item(_item: @ast::item, _wbcx: wb_ctxt, _v: wb_vt) {
 }
 
 fn mk_visitor() -> visit::vt<wb_ctxt> {
-    visit::mk_vt(@{visit_item: visit_item,
-                   visit_stmt: visit_stmt,
-                   visit_expr: visit_expr,
-                   visit_block: visit_block,
-                   visit_pat: visit_pat,
-                   visit_local: visit_local,
-                   .. *visit::default_visitor()})
+    visit::mk_vt(@visit::Visitor {visit_item: visit_item,
+                                  visit_stmt: visit_stmt,
+                                  visit_expr: visit_expr,
+                                  visit_block: visit_block,
+                                  visit_pat: visit_pat,
+                                  visit_local: visit_local,
+                                  .. *visit::default_visitor()})
 }
 
 fn resolve_type_vars_in_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool {
@@ -254,7 +253,7 @@ fn resolve_type_vars_in_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool {
 }
 
 fn resolve_type_vars_in_fn(fcx: @fn_ctxt,
-                           decl: ast::fn_decl,
+                           decl: &ast::fn_decl,
                            blk: ast::blk,
                            self_info: Option<self_info>) -> bool {
     let wbcx = {fcx: fcx, mut success: true};
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index d25c91dfe47..9fa78f01265 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -34,7 +34,7 @@ use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_kind_ext};
 use middle::ty::{type_is_ty_var};
 use middle::ty;
 use middle::typeck::crate_ctxt;
-use middle::typeck::infer::{infer_ctxt, can_mk_subty};
+use middle::typeck::infer::{InferCtxt, can_mk_subty};
 use middle::typeck::infer::{new_infer_ctxt, resolve_ivar};
 use middle::typeck::infer::{resolve_nested_tvar, resolve_type};
 use syntax::ast::{crate, def_id, def_mod, def_ty};
@@ -51,6 +51,7 @@ use syntax::codemap::span;
 use syntax::parse;
 use syntax::visit::{default_simple_visitor, default_visitor};
 use syntax::visit::{mk_simple_visitor, mk_vt, visit_crate, visit_item};
+use syntax::visit::{Visitor, SimpleVisitor};
 use syntax::visit::{visit_mod};
 use util::ppaux::ty_to_str;
 
@@ -69,7 +70,7 @@ struct UniversalQuantificationResult {
     bounds: @~[param_bounds]
 }
 
-fn get_base_type(inference_context: infer_ctxt, span: span, original_type: t)
+fn get_base_type(inference_context: @InferCtxt, span: span, original_type: t)
               -> Option<t> {
 
     let resolved_type;
@@ -116,7 +117,7 @@ fn get_base_type(inference_context: infer_ctxt, span: span, original_type: t)
 }
 
 // Returns the def ID of the base type, if there is one.
-fn get_base_type_def_id(inference_context: infer_ctxt,
+fn get_base_type_def_id(inference_context: @InferCtxt,
                         span: span,
                         original_type: t)
                      -> Option<def_id> {
@@ -181,7 +182,7 @@ fn CoherenceChecker(crate_context: @crate_ctxt) -> CoherenceChecker {
 
 struct CoherenceChecker {
     crate_context: @crate_ctxt,
-    inference_context: infer_ctxt,
+    inference_context: @InferCtxt,
 
     // A mapping from implementations to the corresponding base type
     // definition ID.
@@ -199,7 +200,7 @@ impl CoherenceChecker {
         // Check implementations and traits. This populates the tables
         // containing the inherent methods and extension methods. It also
         // builds up the trait inheritance table.
-        visit_crate(*crate, (), mk_simple_visitor(@{
+        visit_crate(*crate, (), mk_simple_visitor(@SimpleVisitor {
             visit_item: |item| {
                 debug!("(checking coherence) item '%s'",
                        self.crate_context.tcx.sess.str_of(item.ident));
@@ -588,7 +589,7 @@ impl CoherenceChecker {
 
     // Privileged scope checking
     fn check_privileged_scopes(crate: @crate) {
-        visit_crate(*crate, (), mk_vt(@{
+        visit_crate(*crate, (), mk_vt(@Visitor {
             visit_item: |item, _context, visitor| {
                 match /*bad*/copy item.node {
                     item_mod(module_) => {
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 11a932db287..db99689f0ad 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -100,11 +100,13 @@ fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
         }
     }
 
-    visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
-        visit_item: |a|convert(ccx, a),
-        visit_foreign_item: |a|convert_foreign(ccx, a),
-        .. *visit::default_simple_visitor()
-    }));
+    visit::visit_crate(
+        *crate, (),
+        visit::mk_simple_visitor(@visit::SimpleVisitor {
+            visit_item: |a|convert(ccx, a),
+            visit_foreign_item: |a|convert_foreign(ccx, a),
+            .. *visit::default_simple_visitor()
+        }));
 }
 
 impl @crate_ctxt {
diff --git a/src/librustc/middle/typeck/infer/assignment.rs b/src/librustc/middle/typeck/infer/assignment.rs
index 8e524bb8019..62080f4db35 100644
--- a/src/librustc/middle/typeck/infer/assignment.rs
+++ b/src/librustc/middle/typeck/infer/assignment.rs
@@ -63,16 +63,16 @@ use core::prelude::*;
 use middle::ty::TyVar;
 use middle::ty;
 use middle::typeck::infer::{ares, cres};
-use middle::typeck::infer::combine::combine_fields;
+use middle::typeck::infer::combine::CombineFields;
 use middle::typeck::infer::sub::Sub;
-use middle::typeck::infer::to_str::ToStr;
+use middle::typeck::infer::to_str::InferStr;
 use util::common::{indent, indenter};
 
 use core::option;
 use syntax::ast::{m_const, m_imm, m_mutbl};
 use syntax::ast;
 
-fn to_ares(+c: cres<ty::t>) -> ares {
+fn to_ares<T>(+c: cres<T>) -> ares {
     match c {
         Ok(_) => Ok(None),
         Err(ref e) => Err((*e))
@@ -82,13 +82,13 @@ fn to_ares(+c: cres<ty::t>) -> ares {
 // Note: Assign is not actually a combiner, in that it does not
 // conform to the same interface, though it performs a similar
 // function.
-enum Assign = combine_fields;
+enum Assign = CombineFields;
 
 impl Assign {
     fn tys(a: ty::t, b: ty::t) -> ares {
         debug!("Assign.tys(%s => %s)",
-               a.to_str(self.infcx),
-               b.to_str(self.infcx));
+               a.inf_str(self.infcx),
+               b.inf_str(self.infcx));
         let _r = indenter();
 
         debug!("Assign.tys: copying first type");
@@ -146,8 +146,8 @@ priv impl Assign {
         +a_bnd: Option<ty::t>, +b_bnd: Option<ty::t>) -> ares {
 
         debug!("Assign.assign_tys_or_sub(%s => %s, %s => %s)",
-               a.to_str(self.infcx), b.to_str(self.infcx),
-               a_bnd.to_str(self.infcx), b_bnd.to_str(self.infcx));
+               a.inf_str(self.infcx), b.inf_str(self.infcx),
+               a_bnd.inf_str(self.infcx), b_bnd.inf_str(self.infcx));
         let _r = indenter();
 
         fn is_borrowable(v: ty::vstore) -> bool {
@@ -210,18 +210,28 @@ priv impl Assign {
                         let nr_b = ty::mk_fn(self.infcx.tcx, ty::FnTyBase {
                             meta: ty::FnMeta {proto: a_f.meta.proto,
                                               ..b_f.meta},
-                            sig: /*bad*/copy b_f.sig
+                            sig: copy b_f.sig
                         });
                         self.try_assign(0, ty::AutoBorrowFn,
                                         a, nr_b, m_imm, b_f.meta.region)
                     }
 
+                    (ty::ty_fn(ref a_f), ty::ty_fn(ref b_f))
+                    if a_f.meta.proto == ast::ProtoBare => {
+                        let b1_f = ty::FnTyBase {
+                            meta: ty::FnMeta {proto: ast::ProtoBare,
+                                              ..b_f.meta},
+                            sig: copy b_f.sig
+                        };
+                        // Eventually we will need to add some sort of
+                        // adjustment here so that trans can add an
+                        // extra NULL env pointer:
+                        to_ares(Sub(*self).fns(a_f, &b1_f))
+                    }
+
                     // check for &T being assigned to *T:
                     (ty::ty_rptr(_, ref a_t), ty::ty_ptr(ref b_t)) => {
-                        match Sub(*self).mts(*a_t, *b_t) {
-                            Ok(_) => Ok(None),
-                            Err(ref e) => Err((*e))
-                        }
+                        to_ares(Sub(*self).mts(*a_t, *b_t))
                     }
 
                     // otherwise, assignment follows normal subtype rules:
@@ -252,10 +262,10 @@ priv impl Assign {
                   r_b: ty::Region) -> ares {
 
         debug!("try_assign(a=%s, nr_b=%s, m=%?, r_b=%s)",
-               a.to_str(self.infcx),
-               nr_b.to_str(self.infcx),
+               a.inf_str(self.infcx),
+               nr_b.inf_str(self.infcx),
                m,
-               r_b.to_str(self.infcx));
+               r_b.inf_str(self.infcx));
 
         do indent {
             let sub = Sub(*self);
diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs
index d0b17d2ddc3..c5e99bc5c03 100644
--- a/src/librustc/middle/typeck/infer/combine.rs
+++ b/src/librustc/middle/typeck/infer/combine.rs
@@ -61,8 +61,8 @@ use middle::ty;
 use middle::typeck::infer::glb::Glb;
 use middle::typeck::infer::lub::Lub;
 use middle::typeck::infer::sub::Sub;
-use middle::typeck::infer::to_str::ToStr;
-use middle::typeck::infer::{cres, infer_ctxt, ures};
+use middle::typeck::infer::to_str::InferStr;
+use middle::typeck::infer::{cres, InferCtxt, ures, IntType, UintType};
 use util::common::indent;
 
 use core::result::{iter_vec2, map_vec2};
@@ -73,8 +73,8 @@ use syntax::codemap::span;
 
 fn macros() { include!("macros.rs"); } // FIXME(#3114): Macro import/export.
 
-trait combine {
-    fn infcx() -> infer_ctxt;
+trait Combine {
+    fn infcx() -> @InferCtxt;
     fn tag() -> ~str;
     fn a_is_expected() -> bool;
     fn span() -> span;
@@ -105,13 +105,13 @@ trait combine {
                a: ty::vstore, b: ty::vstore) -> cres<ty::vstore>;
 }
 
-pub struct combine_fields {
-    infcx: infer_ctxt,
+pub struct CombineFields {
+    infcx: @InferCtxt,
     a_is_expected: bool,
     span: span,
 }
 
-fn expected_found<C: combine,T>(
+fn expected_found<C:Combine,T>(
     self: &C, +a: T, +b: T) -> ty::expected_found<T> {
 
     if self.a_is_expected() {
@@ -121,7 +121,7 @@ fn expected_found<C: combine,T>(
     }
 }
 
-pub fn eq_tys<C: combine>(self: &C, a: ty::t, b: ty::t) -> ures {
+pub fn eq_tys<C:Combine>(self: &C, a: ty::t, b: ty::t) -> ures {
     let suber = self.sub();
     do self.infcx().try {
         do suber.tys(a, b).chain |_ok| {
@@ -130,10 +130,10 @@ pub fn eq_tys<C: combine>(self: &C, a: ty::t, b: ty::t) -> ures {
     }
 }
 
-fn eq_regions<C: combine>(self: &C, a: ty::Region, b: ty::Region) -> ures {
+fn eq_regions<C:Combine>(self: &C, a: ty::Region, b: ty::Region) -> ures {
     debug!("eq_regions(%s, %s)",
-           a.to_str(self.infcx()),
-           b.to_str(self.infcx()));
+           a.inf_str(self.infcx()),
+           b.inf_str(self.infcx()));
     let sub = self.sub();
     do indent {
         self.infcx().try(|| {
@@ -152,7 +152,7 @@ fn eq_regions<C: combine>(self: &C, a: ty::Region, b: ty::Region) -> ures {
     }
 }
 
-fn eq_opt_regions<C:combine>(
+fn eq_opt_regions<C:Combine>(
     self: &C,
     a: Option<ty::Region>,
     b: Option<ty::Region>) -> cres<Option<ty::Region>> {
@@ -174,17 +174,17 @@ fn eq_opt_regions<C:combine>(
         self.infcx().tcx.sess.bug(
             fmt!("substitution a had opt_region %s and \
                   b had opt_region %s",
-                 a.to_str(self.infcx()),
-                 b.to_str(self.infcx())));
+                 a.inf_str(self.infcx()),
+                 b.inf_str(self.infcx())));
       }
     }
 }
 
-fn super_substs<C:combine>(
+fn super_substs<C:Combine>(
     self: &C, did: ast::def_id,
     a: &ty::substs, b: &ty::substs) -> cres<ty::substs> {
 
-    fn relate_region_param<C:combine>(
+    fn relate_region_param<C:Combine>(
         self: &C,
         did: ast::def_id,
         a: Option<ty::Region>,
@@ -220,8 +220,8 @@ fn super_substs<C:combine>(
             self.infcx().tcx.sess.bug(
                 fmt!("substitution a had opt_region %s and \
                       b had opt_region %s with variance %?",
-                      a.to_str(self.infcx()),
-                      b.to_str(self.infcx()),
+                      a.inf_str(self.infcx()),
+                      b.inf_str(self.infcx()),
                       polyty.region_param));
           }
         }
@@ -238,7 +238,7 @@ fn super_substs<C:combine>(
     }
 }
 
-fn super_tps<C:combine>(
+fn super_tps<C:Combine>(
     self: &C, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> {
 
     // Note: type parameters are always treated as *invariant*
@@ -256,7 +256,7 @@ fn super_tps<C:combine>(
     }
 }
 
-fn super_self_tys<C:combine>(
+fn super_self_tys<C:Combine>(
     self: &C, a: Option<ty::t>, b: Option<ty::t>) -> cres<Option<ty::t>> {
 
     // Note: the self type parameter is (currently) always treated as
@@ -279,7 +279,17 @@ fn super_self_tys<C:combine>(
     }
 }
 
-fn super_flds<C:combine>(
+fn super_protos<C: Combine>(
+    self: &C, p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto>
+{
+    if p1 == p2 {
+        Ok(p1)
+    } else {
+        Err(ty::terr_proto_mismatch(expected_found(self, p1, p2)))
+    }
+}
+
+fn super_flds<C:Combine>(
     self: &C, a: ty::field, b: ty::field) -> cres<ty::field> {
 
     if a.ident == b.ident {
@@ -292,7 +302,7 @@ fn super_flds<C:combine>(
     }
 }
 
-fn super_modes<C:combine>(
+fn super_modes<C:Combine>(
     self: &C, a: ast::mode, b: ast::mode)
     -> cres<ast::mode> {
 
@@ -300,7 +310,7 @@ fn super_modes<C:combine>(
     ty::unify_mode(tcx, expected_found(self, a, b))
 }
 
-fn super_args<C:combine>(
+fn super_args<C:Combine>(
     self: &C, a: ty::arg, b: ty::arg)
     -> cres<ty::arg> {
 
@@ -311,7 +321,7 @@ fn super_args<C:combine>(
     }
 }
 
-fn super_vstores<C:combine>(
+fn super_vstores<C:Combine>(
     self: &C, vk: ty::terr_vstore_kind,
     a: ty::vstore, b: ty::vstore) -> cres<ty::vstore>
 {
@@ -334,7 +344,7 @@ fn super_vstores<C:combine>(
     }
 }
 
-fn super_fn_metas<C:combine>(
+fn super_fn_metas<C:Combine>(
     self: &C, a_f: &ty::FnMeta, b_f: &ty::FnMeta) -> cres<ty::FnMeta>
 {
     let p = if_ok!(self.protos(a_f.proto, b_f.proto));
@@ -343,17 +353,18 @@ fn super_fn_metas<C:combine>(
     let onceness = if_ok!(self.oncenesses(a_f.onceness, b_f.onceness));
     Ok(FnMeta {purity: purity,
                proto: p,
-               region: r,
                onceness: onceness,
+               region: r,
                bounds: a_f.bounds}) // XXX: This is wrong!
 }
 
-fn super_fn_sigs<C:combine>(
-    self: &C, a_f: &ty::FnSig, b_f: &ty::FnSig) -> cres<ty::FnSig> {
-    fn argvecs<C:combine>(self: &C,
+fn super_fn_sigs<C:Combine>(
+    self: &C, a_f: &ty::FnSig, b_f: &ty::FnSig) -> cres<ty::FnSig>
+{
+    fn argvecs<C:Combine>(self: &C,
                           +a_args: ~[ty::arg],
-                          +b_args: ~[ty::arg]) -> cres<~[ty::arg]> {
-
+                          +b_args: ~[ty::arg]) -> cres<~[ty::arg]>
+    {
         if vec::same_length(a_args, b_args) {
             map_vec2(a_args, b_args, |a, b| self.args(*a, *b))
         } else {
@@ -369,19 +380,17 @@ fn super_fn_sigs<C:combine>(
     }
 }
 
-fn super_fns<C:combine>(
+fn super_fns<C:Combine>(
     self: &C, a_f: &ty::FnTy, b_f: &ty::FnTy) -> cres<ty::FnTy>
 {
-    do self.fn_metas(&a_f.meta, &b_f.meta).chain |m| {
-        do self.fn_sigs(&a_f.sig, &b_f.sig).chain |s| {
-            Ok(FnTyBase {meta: m, sig: s})
-        }
-    }
+    let m = if_ok!(self.fn_metas(&a_f.meta, &b_f.meta));
+    let s = if_ok!(self.fn_sigs(&a_f.sig, &b_f.sig));
+    Ok(FnTyBase {meta: m, sig: s})
 }
 
-fn super_tys<C:combine>(
-    self: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
-
+fn super_tys<C:Combine>(
+    self: &C, a: ty::t, b: ty::t) -> cres<ty::t>
+{
     let tcx = self.infcx().tcx;
     match (/*bad*/copy ty::get(a).sty, /*bad*/copy ty::get(b).sty) {
       // The "subtype" ought to be handling cases involving bot or var:
@@ -392,32 +401,49 @@ fn super_tys<C:combine>(
         tcx.sess.bug(
             fmt!("%s: bot and var types should have been handled (%s,%s)",
                  self.tag(),
-                 a.to_str(self.infcx()),
-                 b.to_str(self.infcx())));
+                 a.inf_str(self.infcx()),
+                 b.inf_str(self.infcx())));
       }
 
       // Relate integral variables to other types
       (ty::ty_infer(IntVar(a_id)), ty::ty_infer(IntVar(b_id))) => {
-        self.infcx().int_vars(a_id, b_id).then(|| Ok(a) )
+        if_ok!(self.infcx().simple_vars(&self.infcx().int_var_bindings,
+                                        ty::terr_no_integral_type,
+                                        a_id, b_id));
+        Ok(a)
       }
-      (ty::ty_infer(IntVar(a_id)), ty::ty_int(_)) |
-      (ty::ty_infer(IntVar(a_id)), ty::ty_uint(_)) => {
-        self.infcx().int_var_sub_t(a_id, b).then(|| Ok(a) )
+      (ty::ty_infer(IntVar(v_id)), ty::ty_int(v)) |
+      (ty::ty_int(v), ty::ty_infer(IntVar(v_id))) => {
+        if v == ast::ty_char {
+            Err(ty::terr_integer_as_char)
+        } else {
+            if_ok!(self.infcx().simple_var_t(&self.infcx().int_var_bindings,
+                                             ty::terr_no_integral_type,
+                                             v_id, IntType(v)));
+            Ok(ty::mk_mach_int(tcx, v))
+        }
       }
-      (ty::ty_int(_), ty::ty_infer(IntVar(b_id))) |
-      (ty::ty_uint(_), ty::ty_infer(IntVar(b_id))) => {
-        self.infcx().t_sub_int_var(a, b_id).then(|| Ok(a) )
+      (ty::ty_infer(IntVar(v_id)), ty::ty_uint(v)) |
+      (ty::ty_uint(v), ty::ty_infer(IntVar(v_id))) => {
+        if_ok!(self.infcx().simple_var_t(&self.infcx().int_var_bindings,
+                                         ty::terr_no_integral_type,
+                                         v_id, UintType(v)));
+        Ok(ty::mk_mach_uint(tcx, v))
       }
 
       // Relate floating-point variables to other types
       (ty::ty_infer(FloatVar(a_id)), ty::ty_infer(FloatVar(b_id))) => {
-        self.infcx().float_vars(a_id, b_id).then(|| Ok(a) )
-      }
-      (ty::ty_infer(FloatVar(a_id)), ty::ty_float(_)) => {
-        self.infcx().float_var_sub_t(a_id, b).then(|| Ok(a) )
+        if_ok!(self.infcx().simple_vars(&self.infcx().float_var_bindings,
+                                        ty::terr_no_floating_point_type,
+                                        a_id, b_id));
+        Ok(a)
       }
-      (ty::ty_float(_), ty::ty_infer(FloatVar(b_id))) => {
-        self.infcx().t_sub_float_var(a, b_id).then(|| Ok(a) )
+      (ty::ty_infer(FloatVar(v_id)), ty::ty_float(v)) |
+      (ty::ty_float(v), ty::ty_infer(FloatVar(v_id))) => {
+        if_ok!(self.infcx().simple_var_t(&self.infcx().float_var_bindings,
+                                         ty::terr_no_floating_point_type,
+                                         v_id, v));
+        Ok(ty::mk_mach_float(tcx, v))
       }
 
       (ty::ty_int(_), _) |
diff --git a/src/librustc/middle/typeck/infer/floating.rs b/src/librustc/middle/typeck/infer/floating.rs
deleted file mode 100644
index 68adeeb82db..00000000000
--- a/src/librustc/middle/typeck/infer/floating.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-
-Code related to floating-point type inference.
-
-*/
-
-use core::prelude::*;
-
-use middle::ty::{get, ty_float};
-use middle::ty;
-use middle::typeck::infer::to_str::ToStr;
-
-use core::uint;
-use syntax::ast;
-
-// Bitvector to represent sets of floating-point types.
-pub enum float_ty_set = uint;
-
-// Constants representing singleton sets containing each of the floating-point
-// types.
-pub const FLOAT_TY_SET_EMPTY: uint = 0b000u;
-pub const FLOAT_TY_SET_FLOAT: uint = 0b001u;
-pub const FLOAT_TY_SET_F32:   uint = 0b010u;
-pub const FLOAT_TY_SET_F64:   uint = 0b100u;
-
-pub fn float_ty_set_all() -> float_ty_set {
-    float_ty_set(FLOAT_TY_SET_FLOAT | FLOAT_TY_SET_F32 | FLOAT_TY_SET_F64)
-}
-
-pub fn intersection(a: float_ty_set, b: float_ty_set) -> float_ty_set {
-    float_ty_set(*a & *b)
-}
-
-pub fn single_type_contained_in(tcx: ty::ctxt, a: float_ty_set)
-                             -> Option<ty::t> {
-    debug!("single_type_contained_in(a=%s)", uint::to_str(*a, 10));
-
-    if *a == FLOAT_TY_SET_FLOAT { return Some(ty::mk_float(tcx)); }
-    if *a == FLOAT_TY_SET_F32   { return Some(ty::mk_f32(tcx));   }
-    if *a == FLOAT_TY_SET_F64   { return Some(ty::mk_f64(tcx));   }
-    return None;
-}
-
-pub fn convert_floating_point_ty_to_float_ty_set(tcx: ty::ctxt, t: ty::t)
-                                              -> float_ty_set {
-    match get(t).sty {
-        ty::ty_float(ast::ty_f)     => float_ty_set(FLOAT_TY_SET_FLOAT),
-        ty::ty_float(ast::ty_f32)   => float_ty_set(FLOAT_TY_SET_F32),
-        ty::ty_float(ast::ty_f64)   => float_ty_set(FLOAT_TY_SET_F64),
-        _ => tcx.sess.bug(~"non-floating-point type passed to \
-                            convert_floating_point_ty_to_float_ty_set()")
-    }
-}
-
diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs
index bfe81245ecb..4d697ad3433 100644
--- a/src/librustc/middle/typeck/infer/glb.rs
+++ b/src/librustc/middle/typeck/infer/glb.rs
@@ -17,7 +17,7 @@ use middle::typeck::infer::glb::Glb;
 use middle::typeck::infer::lattice::*;
 use middle::typeck::infer::lub::Lub;
 use middle::typeck::infer::sub::Sub;
-use middle::typeck::infer::to_str::ToStr;
+use middle::typeck::infer::to_str::InferStr;
 use middle::typeck::isr_alist;
 use syntax::ast::{Many, Once, extern_fn, impure_fn, m_const, m_imm, m_mutbl};
 use syntax::ast::{noreturn, pure_fn, ret_style, return_val, unsafe_fn};
@@ -25,10 +25,10 @@ use util::ppaux::mt_to_str;
 
 use std::list;
 
-enum Glb = combine_fields;  // "greatest lower bound" (common subtype)
+enum Glb = CombineFields;  // "greatest lower bound" (common subtype)
 
-impl Glb: combine {
-    fn infcx() -> infer_ctxt { self.infcx }
+impl Glb: Combine {
+    fn infcx() -> @InferCtxt { self.infcx }
     fn tag() -> ~str { ~"glb" }
     fn a_is_expected() -> bool { self.a_is_expected }
     fn span() -> span { self.span }
@@ -94,10 +94,6 @@ impl Glb: combine {
         Lub(*self).tys(a, b)
     }
 
-    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
-        if p1 == p2 {Ok(p1)} else {Ok(ast::ProtoBare)}
-    }
-
     fn purities(a: purity, b: purity) -> cres<purity> {
         match (a, b) {
           (pure_fn, _) | (_, pure_fn) => Ok(pure_fn),
@@ -117,8 +113,8 @@ impl Glb: combine {
     fn regions(a: ty::Region, b: ty::Region) -> cres<ty::Region> {
         debug!("%s.regions(%?, %?)",
                self.tag(),
-               a.to_str(self.infcx),
-               b.to_str(self.infcx));
+               a.inf_str(self.infcx),
+               b.inf_str(self.infcx));
 
         do indent {
             self.infcx.region_vars.glb_regions(self.span, a, b)
@@ -130,7 +126,7 @@ impl Glb: combine {
     }
 
     fn tys(a: ty::t, b: ty::t) -> cres<ty::t> {
-        lattice_tys(&self, a, b)
+        super_lattice_tys(&self, a, b)
     }
 
     // Traits please (FIXME: #2794):
@@ -152,12 +148,12 @@ impl Glb: combine {
         super_args(&self, a, b)
     }
 
-    fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
+    fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
         // Note: this is a subtle algorithm.  For a full explanation,
         // please see the large comment in `region_inference.rs`.
 
-        debug!("%s.fns(%?, %?)",
-               self.tag(), a.to_str(self.infcx), b.to_str(self.infcx));
+        debug!("%s.fn_sigs(%?, %?)",
+               self.tag(), a.inf_str(self.infcx), b.inf_str(self.infcx));
         let _indenter = indenter();
 
         // Take a snapshot.  We'll never roll this back, but in later
@@ -177,20 +173,20 @@ impl Glb: combine {
         let b_vars = var_ids(&self, b_isr);
 
         // Collect constraints.
-        let fn_ty0 = if_ok!(super_fns(&self, &a_with_fresh, &b_with_fresh));
-        debug!("fn_ty0 = %s", fn_ty0.to_str(self.infcx));
+        let sig0 = if_ok!(super_fn_sigs(&self, &a_with_fresh, &b_with_fresh));
+        debug!("sig0 = %s", sig0.inf_str(self.infcx));
 
         // Generalize the regions appearing in fn_ty0 if possible
         let new_vars =
             self.infcx.region_vars.vars_created_since_snapshot(snapshot);
-        let fn_ty1 =
+        let sig1 =
             self.infcx.fold_regions_in_sig(
-                &fn_ty0,
+                &sig0,
                 |r, _in_fn| generalize_region(&self, snapshot,
                                               new_vars, a_isr, a_vars, b_vars,
                                               r));
-        debug!("fn_ty1 = %s", fn_ty1.to_str(self.infcx));
-        return Ok(move fn_ty1);
+        debug!("sig1 = %s", sig1.inf_str(self.infcx));
+        return Ok(move sig1);
 
         fn generalize_region(self: &Glb,
                              snapshot: uint,
@@ -271,12 +267,16 @@ impl Glb: combine {
         }
     }
 
-    fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
-        super_fn_metas(&self, a, b)
+    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
+        super_protos(&self, p1, p2)
     }
 
-    fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
-        super_fn_sigs(&self, a, b)
+    fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
+        super_fns(&self, a, b)
+    }
+
+    fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
+        super_fn_metas(&self, a, b)
     }
 
     fn substs(did: ast::def_id,
diff --git a/src/librustc/middle/typeck/infer/integral.rs b/src/librustc/middle/typeck/infer/integral.rs
deleted file mode 100644
index aa67c1371f9..00000000000
--- a/src/librustc/middle/typeck/infer/integral.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-
-Code related to integral type inference.
-
-*/
-
-use core::prelude::*;
-
-use middle::ty::{get, ty_int, ty_uint};
-use middle::ty;
-use middle::typeck::infer::to_str::ToStr;
-
-use core::uint;
-use syntax::ast;
-
-// Bitvector to represent sets of integral types
-enum int_ty_set = uint;
-
-// Constants representing singleton sets containing each of the
-// integral types
-const INT_TY_SET_EMPTY : uint = 0b00_0000_0000u;
-const INT_TY_SET_i8    : uint = 0b00_0000_0001u;
-const INT_TY_SET_u8    : uint = 0b00_0000_0010u;
-const INT_TY_SET_i16   : uint = 0b00_0000_0100u;
-const INT_TY_SET_u16   : uint = 0b00_0000_1000u;
-const INT_TY_SET_i32   : uint = 0b00_0001_0000u;
-const INT_TY_SET_u32   : uint = 0b00_0010_0000u;
-const INT_TY_SET_i64   : uint = 0b00_0100_0000u;
-const INT_TY_SET_u64   : uint = 0b00_1000_0000u;
-const INT_TY_SET_i     : uint = 0b01_0000_0000u;
-const INT_TY_SET_u     : uint = 0b10_0000_0000u;
-
-fn int_ty_set_all()  -> int_ty_set {
-    int_ty_set(INT_TY_SET_i8  | INT_TY_SET_u8 |
-               INT_TY_SET_i16 | INT_TY_SET_u16 |
-               INT_TY_SET_i32 | INT_TY_SET_u32 |
-               INT_TY_SET_i64 | INT_TY_SET_u64 |
-               INT_TY_SET_i   | INT_TY_SET_u)
-}
-
-fn intersection(a: int_ty_set, b: int_ty_set) -> int_ty_set {
-    int_ty_set(*a & *b)
-}
-
-fn single_type_contained_in(tcx: ty::ctxt, a: int_ty_set) ->
-    Option<ty::t> {
-    debug!("single_type_contained_in(a=%s)", uint::to_str(*a, 10u));
-
-    if *a == INT_TY_SET_i8    { return Some(ty::mk_i8(tcx)); }
-    if *a == INT_TY_SET_u8    { return Some(ty::mk_u8(tcx)); }
-    if *a == INT_TY_SET_i16   { return Some(ty::mk_i16(tcx)); }
-    if *a == INT_TY_SET_u16   { return Some(ty::mk_u16(tcx)); }
-    if *a == INT_TY_SET_i32   { return Some(ty::mk_i32(tcx)); }
-    if *a == INT_TY_SET_u32   { return Some(ty::mk_u32(tcx)); }
-    if *a == INT_TY_SET_i64   { return Some(ty::mk_i64(tcx)); }
-    if *a == INT_TY_SET_u64   { return Some(ty::mk_u64(tcx)); }
-    if *a == INT_TY_SET_i     { return Some(ty::mk_int(tcx)); }
-    if *a == INT_TY_SET_u     { return Some(ty::mk_uint(tcx)); }
-    return None;
-}
-
-fn convert_integral_ty_to_int_ty_set(tcx: ty::ctxt, t: ty::t)
-    -> int_ty_set {
-
-    match get(t).sty {
-      ty_int(int_ty) => match int_ty {
-        ast::ty_i8   => int_ty_set(INT_TY_SET_i8),
-        ast::ty_i16  => int_ty_set(INT_TY_SET_i16),
-        ast::ty_i32  => int_ty_set(INT_TY_SET_i32),
-        ast::ty_i64  => int_ty_set(INT_TY_SET_i64),
-        ast::ty_i    => int_ty_set(INT_TY_SET_i),
-        ast::ty_char => tcx.sess.bug(
-            ~"char type passed to convert_integral_ty_to_int_ty_set()")
-      },
-      ty_uint(uint_ty) => match uint_ty {
-        ast::ty_u8  => int_ty_set(INT_TY_SET_u8),
-        ast::ty_u16 => int_ty_set(INT_TY_SET_u16),
-        ast::ty_u32 => int_ty_set(INT_TY_SET_u32),
-        ast::ty_u64 => int_ty_set(INT_TY_SET_u64),
-        ast::ty_u   => int_ty_set(INT_TY_SET_u)
-      },
-      _ => tcx.sess.bug(~"non-integral type passed to \
-                          convert_integral_ty_to_int_ty_set()")
-    }
-}
diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs
index 4437a1e780d..9783aee0848 100644
--- a/src/librustc/middle/typeck/infer/lattice.rs
+++ b/src/librustc/middle/typeck/infer/lattice.rs
@@ -8,162 +8,503 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+/*!
+ *
+ * # Lattice Variables
+ *
+ * This file contains generic code for operating on inference variables
+ * that are characterized by an upper- and lower-bound.  The logic and
+ * reasoning is explained in detail in the large comment in `infer.rs`.
+ *
+ * The code in here is defined quite generically so that it can be
+ * applied both to type variables, which represent types being inferred,
+ * and fn variables, which represent function types being inferred.
+ * It may eventually be applied to ther types as well, who knows.
+ * In some cases, the functions are also generic with respect to the
+ * operation on the lattice (GLB vs LUB).
+ *
+ * Although all the functions are generic, we generally write the
+ * comments in a way that is specific to type variables and the LUB
+ * operation.  It's just easier that way.
+ *
+ * In general all of the functions are defined parametrically
+ * over a `LatticeValue`, which is a value defined with respect to
+ * a lattice.
+ */
+
 use core::prelude::*;
 
 use middle::ty::{RegionVid, TyVar};
 use middle::ty;
+use middle::typeck::isr_alist;
 use middle::typeck::infer::*;
 use middle::typeck::infer::combine::*;
 use middle::typeck::infer::glb::Glb;
 use middle::typeck::infer::lub::Lub;
 use middle::typeck::infer::unify::*;
-use middle::typeck::infer::to_str::ToStr;
-use middle::typeck::isr_alist;
+use middle::typeck::infer::sub::Sub;
+use middle::typeck::infer::lub::Lub;
+use middle::typeck::infer::glb::Glb;
+use middle::typeck::infer::to_str::InferStr;
 
 use std::list;
 
+trait LatticeValue {
+    static fn sub(cf: &CombineFields, a: &self, b: &self) -> ures;
+    static fn lub(cf: &CombineFields, a: &self, b: &self) -> cres<self>;
+    static fn glb(cf: &CombineFields, a: &self, b: &self) -> cres<self>;
+}
+
+type LatticeOp<T> = &fn(cf: &CombineFields, a: &T, b: &T) -> cres<T>;
+
+impl ty::t: LatticeValue {
+    static fn sub(cf: &CombineFields, a: &ty::t, b: &ty::t) -> ures {
+        Sub(*cf).tys(*a, *b).to_ures()
+    }
+
+    static fn lub(cf: &CombineFields, a: &ty::t, b: &ty::t) -> cres<ty::t> {
+        Lub(*cf).tys(*a, *b)
+    }
+
+    static fn glb(cf: &CombineFields, a: &ty::t, b: &ty::t) -> cres<ty::t> {
+        Glb(*cf).tys(*a, *b)
+    }
+}
+
+impl FnMeta: LatticeValue {
+    static fn sub(cf: &CombineFields,
+                  a: &FnMeta, b: &FnMeta) -> ures {
+        Sub(*cf).fn_metas(a, b).to_ures()
+    }
+
+    static fn lub(cf: &CombineFields,
+                  a: &FnMeta, b: &FnMeta) -> cres<FnMeta> {
+        Lub(*cf).fn_metas(a, b)
+    }
+
+    static fn glb(cf: &CombineFields,
+                  a: &FnMeta, b: &FnMeta) -> cres<FnMeta> {
+        Glb(*cf).fn_metas(a, b)
+    }
+}
+
+impl CombineFields {
+    fn var_sub_var<V:Copy Eq Vid ToStr, T:Copy InferStr LatticeValue>(
+        &self,
+        vb: &ValsAndBindings<V, Bounds<T>>,
+        +a_id: V,
+        +b_id: V) -> ures
+    {
+        /*!
+         *
+         * Make one variable a subtype of another variable.  This is a
+         * subtle and tricky process, as described in detail at the
+         * top of infer.rs*/
+
+        // Need to make sub_id a subtype of sup_id.
+        let node_a = self.infcx.get(vb, a_id);
+        let node_b = self.infcx.get(vb, b_id);
+        let a_id = node_a.root;
+        let b_id = node_b.root;
+        let a_bounds = node_a.possible_types;
+        let b_bounds = node_b.possible_types;
+
+        debug!("vars(%s=%s <: %s=%s)",
+               a_id.to_str(), a_bounds.inf_str(self.infcx),
+               b_id.to_str(), b_bounds.inf_str(self.infcx));
+
+        if a_id == b_id { return uok(); }
+
+        // If both A's UB and B's LB have already been bound to types,
+        // see if we can make those types subtypes.
+        match (a_bounds.ub, b_bounds.lb) {
+            (Some(ref a_ub), Some(ref b_lb)) => {
+                let r = self.infcx.try(
+                    || LatticeValue::sub(self, a_ub, b_lb));
+                match r {
+                    Ok(()) => {
+                        return Ok(());
+                    }
+                    Err(_) => { /*fallthrough */ }
+                }
+            }
+            _ => { /*fallthrough*/ }
+        }
+
+        // Otherwise, we need to merge A and B so as to guarantee that
+        // A remains a subtype of B.  Actually, there are other options,
+        // but that's the route we choose to take.
+
+        self.infcx.unify(vb, &node_a, &node_b, |new_root, new_rank| {
+            self.set_var_to_merged_bounds(vb, new_root,
+                                          &a_bounds, &b_bounds,
+                                          new_rank)
+        })
+    }
+
+    /// make variable a subtype of T
+    fn var_sub_t<V:Copy Eq Vid ToStr, T:Copy InferStr LatticeValue>(
+        &self,
+        vb: &ValsAndBindings<V, Bounds<T>>,
+        +a_id: V,
+        +b: T) -> ures
+    {
+        /*!
+         *
+         * Make a variable (`a_id`) a subtype of the concrete type `b` */
+
+        let node_a = self.infcx.get(vb, a_id);
+        let a_id = node_a.root;
+        let a_bounds = &node_a.possible_types;
+        let b_bounds = &{lb: None, ub: Some(b)};
+
+        debug!("var_sub_t(%s=%s <: %s)",
+               a_id.to_str(),
+               a_bounds.inf_str(self.infcx),
+               b.inf_str(self.infcx));
+
+        self.set_var_to_merged_bounds(
+            vb, a_id, a_bounds, b_bounds, node_a.rank)
+    }
+
+    fn t_sub_var<V:Copy Eq Vid ToStr, T:Copy InferStr LatticeValue>(
+        &self,
+        vb: &ValsAndBindings<V, Bounds<T>>,
+        +a: T,
+        +b_id: V) -> ures
+    {
+        /*!
+         *
+         * Make a concrete type (`a`) a subtype of the variable `b_id` */
+
+        let a_bounds = &{lb: Some(a), ub: None};
+        let node_b = self.infcx.get(vb, b_id);
+        let b_id = node_b.root;
+        let b_bounds = &node_b.possible_types;
+
+        debug!("t_sub_var(%s <: %s=%s)",
+               a.inf_str(self.infcx),
+               b_id.to_str(),
+               b_bounds.inf_str(self.infcx));
+
+        self.set_var_to_merged_bounds(
+            vb, b_id, a_bounds, b_bounds, node_b.rank)
+    }
+
+    fn merge_bnd<T:Copy InferStr LatticeValue>(
+        &self,
+        a: &Bound<T>,
+        b: &Bound<T>,
+        lattice_op: LatticeOp<T>)
+        -> cres<Bound<T>>
+    {
+        /*!
+         *
+         * Combines two bounds into a more general bound. */
+
+        debug!("merge_bnd(%s,%s)",
+               a.inf_str(self.infcx),
+               b.inf_str(self.infcx));
+        let _r = indenter();
+
+        match (*a, *b) {
+            (None,          None) => Ok(None),
+            (Some(_),       None) => Ok(*a),
+            (None,          Some(_)) => Ok(*b),
+            (Some(ref v_a), Some(ref v_b)) => {
+                do lattice_op(self, v_a, v_b).chain |v| {
+                    Ok(Some(v))
+                }
+            }
+        }
+    }
+
+    fn set_var_to_merged_bounds<V:Copy Eq Vid ToStr,
+                                T:Copy InferStr LatticeValue>(
+        &self,
+        vb: &ValsAndBindings<V, Bounds<T>>,
+        +v_id: V,
+        a: &Bounds<T>,
+        b: &Bounds<T>,
+        rank: uint) -> ures
+    {
+        /*!
+         *
+         * Updates the bounds for the variable `v_id` to be the intersection
+         * of `a` and `b`.  That is, the new bounds for `v_id` will be
+         * a bounds c such that:
+         *    c.ub <: a.ub
+         *    c.ub <: b.ub
+         *    a.lb <: c.lb
+         *    b.lb <: c.lb
+         * If this cannot be achieved, the result is failure. */
+
+        // Think of the two diamonds, we want to find the
+        // intersection.  There are basically four possibilities (you
+        // can swap A/B in these pictures):
+        //
+        //       A         A
+        //      / \       / \
+        //     / B \     / B \
+        //    / / \ \   / / \ \
+        //   * *   * * * /   * *
+        //    \ \ / /   \   / /
+        //     \ B /   / \ / /
+        //      \ /   *   \ /
+        //       A     \ / A
+        //              B
+
+        debug!("merge(%s,%s,%s)",
+               v_id.to_str(),
+               a.inf_str(self.infcx),
+               b.inf_str(self.infcx));
+        let _indent = indenter();
+
+        // First, relate the lower/upper bounds of A and B.
+        // Note that these relations *must* hold for us to
+        // to be able to merge A and B at all, and relating
+        // them explicitly gives the type inferencer more
+        // information and helps to produce tighter bounds
+        // when necessary.
+        let () = if_ok!(self.bnds(&a.lb, &b.ub));
+        let () = if_ok!(self.bnds(&b.lb, &a.ub));
+        let ub = if_ok!(self.merge_bnd(&a.ub, &b.ub, LatticeValue::glb));
+        let lb = if_ok!(self.merge_bnd(&a.lb, &b.lb, LatticeValue::lub));
+        let bounds = {lb: lb, ub: ub};
+        debug!("merge(%s): bounds=%s",
+               v_id.to_str(),
+               bounds.inf_str(self.infcx));
+
+        // the new bounds must themselves
+        // be relatable:
+        let () = if_ok!(self.bnds(&bounds.lb, &bounds.ub));
+        self.infcx.set(vb, v_id, Root(bounds, rank));
+        uok()
+    }
+
+    fn bnds<T:Copy InferStr LatticeValue>(
+        &self,
+        a: &Bound<T>,
+        b: &Bound<T>) -> ures
+    {
+        debug!("bnds(%s <: %s)", a.inf_str(self.infcx),
+               b.inf_str(self.infcx));
+        let _r = indenter();
+
+        match (*a, *b) {
+            (None, None) |
+            (Some(_), None) |
+            (None, Some(_)) => {
+                uok()
+            }
+            (Some(ref t_a), Some(ref t_b)) => {
+                LatticeValue::sub(self, t_a, t_b)
+            }
+        }
+    }
+}
+
 // ______________________________________________________________________
 // Lattice operations on variables
 //
 // This is common code used by both LUB and GLB to compute the LUB/GLB
 // for pairs of variables or for variables and values.
 
-trait lattice_ops {
-    fn bnd(b: bounds<ty::t>) -> Option<ty::t>;
-    fn with_bnd(b: bounds<ty::t>, t: ty::t) -> bounds<ty::t>;
+trait LatticeDir {
+    fn combine_fields() -> CombineFields;
+    fn bnd<T:Copy>(b: &Bounds<T>) -> Option<T>;
+    fn with_bnd<T:Copy>(b: &Bounds<T>, +t: T) -> Bounds<T>;
+}
+
+trait TyLatticeDir {
     fn ty_bot(t: ty::t) -> cres<ty::t>;
 }
 
-impl Lub: lattice_ops {
-    fn bnd(b: bounds<ty::t>) -> Option<ty::t> { b.ub }
-    fn with_bnd(b: bounds<ty::t>, t: ty::t) -> bounds<ty::t> {
-        {ub: Some(t),.. b}
+impl Lub: LatticeDir {
+    fn combine_fields() -> CombineFields { *self }
+    fn bnd<T:Copy>(b: &Bounds<T>) -> Option<T> { b.ub }
+    fn with_bnd<T:Copy>(b: &Bounds<T>, +t: T) -> Bounds<T> {
+        {ub: Some(t), ..*b}
     }
+}
+
+impl Lub: TyLatticeDir {
     fn ty_bot(t: ty::t) -> cres<ty::t> {
         Ok(t)
     }
 }
 
-impl Glb: lattice_ops {
-    fn bnd(b: bounds<ty::t>) -> Option<ty::t> { b.lb }
-    fn with_bnd(b: bounds<ty::t>, t: ty::t) -> bounds<ty::t> {
-        {lb: Some(t),.. b}
+impl Glb: LatticeDir {
+    fn combine_fields() -> CombineFields { *self }
+    fn bnd<T:Copy>(b: &Bounds<T>) -> Option<T> { b.lb }
+    fn with_bnd<T:Copy>(b: &Bounds<T>, +t: T) -> Bounds<T> {
+        {lb: Some(t), ..*b}
     }
+}
+
+impl Glb: TyLatticeDir {
     fn ty_bot(_t: ty::t) -> cres<ty::t> {
         Ok(ty::mk_bot(self.infcx.tcx))
     }
 }
 
-fn lattice_tys<L:lattice_ops combine>(
-    self: &L, a: ty::t, b: ty::t) -> cres<ty::t> {
-
+fn super_lattice_tys<L:LatticeDir TyLatticeDir Combine>(
+    self: &L,
+    a: ty::t,
+    b: ty::t) -> cres<ty::t>
+{
     debug!("%s.lattice_tys(%s, %s)", self.tag(),
-           a.to_str(self.infcx()),
-           b.to_str(self.infcx()));
-    if a == b { return Ok(a); }
-    do indent {
-        match (ty::get(a).sty, ty::get(b).sty) {
-          (ty::ty_bot, _) => self.ty_bot(b),
-          (_, ty::ty_bot) => self.ty_bot(a),
-
-          (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => {
-            lattice_vars(self, a, a_id, b_id,
-                         |x, y| self.tys(x, y) )
-          }
-
-          (ty::ty_infer(TyVar(a_id)), _) => {
-            lattice_var_and_t(self, a_id, b,
-                              |x, y| self.tys(x, y) )
-          }
-
-          (_, ty::ty_infer(TyVar(b_id))) => {
-            lattice_var_and_t(self, b_id, a,
-                              |x, y| self.tys(x, y) )
-          }
-          _ => {
-            super_tys(self, a, b)
-          }
+           a.inf_str(self.infcx()),
+           b.inf_str(self.infcx()));
+    let _r = indenter();
+
+    if a == b {
+        return Ok(a);
+    }
+
+    let tcx = self.infcx().tcx;
+
+    match (ty::get(a).sty, ty::get(b).sty) {
+        (ty::ty_bot, _) => { return self.ty_bot(b); }
+        (_, ty::ty_bot) => { return self.ty_bot(a); }
+
+        (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => {
+            let r = if_ok!(lattice_vars(self, &self.infcx().ty_var_bindings,
+                                        a_id, b_id,
+                                        |x, y| self.tys(*x, *y)));
+            return match r {
+                VarResult(v) => Ok(ty::mk_var(tcx, v)),
+                ValueResult(t) => Ok(t)
+            };
+        }
+
+        (ty::ty_infer(TyVar(a_id)), _) => {
+            return lattice_var_and_t(self, &self.infcx().ty_var_bindings,
+                                     a_id, &b,
+                                     |x, y| self.tys(*x, *y));
+        }
+
+        (_, ty::ty_infer(TyVar(b_id))) => {
+            return lattice_var_and_t(self, &self.infcx().ty_var_bindings,
+                                     b_id, &a,
+                                     |x, y| self.tys(*x, *y));
+        }
+
+        _ => {
+            return super_tys(self, a, b);
         }
     }
 }
 
-fn lattice_vars<L:lattice_ops combine>(
-    self: &L, +a_t: ty::t, +a_vid: ty::TyVid, +b_vid: ty::TyVid,
-    c_ts: fn(ty::t, ty::t) -> cres<ty::t>) -> cres<ty::t> {
+type LatticeDirOp<T> = &fn(a: &T, b: &T) -> cres<T>;
 
-    // The comments in this function are written for LUB and types,
-    // but they apply equally well to GLB and regions if you inverse
-    // upper/lower/sub/super/etc.
+enum LatticeVarResult<V,T> {
+    VarResult(V),
+    ValueResult(T)
+}
 
-    // Need to find a type that is a supertype of both a and b:
-    let vb = &self.infcx().ty_var_bindings;
+/**
+ * Computes the LUB or GLB of two bounded variables.  These could be any
+ * sort of variables, but in the comments on this function I'll assume
+ * we are doing an LUB on two type variables.
+ *
+ * This computation can be done in one of two ways:
+ *
+ * - If both variables have an upper bound, we may just compute the
+ *   LUB of those bounds and return that, in which case we are
+ *   returning a type.  This is indicated with a `ValueResult` return.
+ *
+ * - If the variables do not both have an upper bound, we will unify
+ *   the variables and return the unified variable, in which case the
+ *   result is a variable.  This is indicated with a `VarResult`
+ *   return. */
+fn lattice_vars<L:LatticeDir Combine,
+                V:Copy Eq Vid ToStr,
+                T:Copy InferStr LatticeValue>(
+    self: &L,                           // defines whether we want LUB or GLB
+    vb: &ValsAndBindings<V, Bounds<T>>, // relevant variable bindings
+    +a_vid: V,                          // first variable
+    +b_vid: V,                          // second variable
+    lattice_dir_op: LatticeDirOp<T>)    // LUB or GLB operation on types
+    -> cres<LatticeVarResult<V,T>>
+{
     let nde_a = self.infcx().get(vb, a_vid);
     let nde_b = self.infcx().get(vb, b_vid);
     let a_vid = nde_a.root;
     let b_vid = nde_b.root;
-    let a_bounds = nde_a.possible_types;
-    let b_bounds = nde_b.possible_types;
+    let a_bounds = &nde_a.possible_types;
+    let b_bounds = &nde_b.possible_types;
 
     debug!("%s.lattice_vars(%s=%s <: %s=%s)",
            self.tag(),
-           a_vid.to_str(), a_bounds.to_str(self.infcx()),
-           b_vid.to_str(), b_bounds.to_str(self.infcx()));
+           a_vid.to_str(), a_bounds.inf_str(self.infcx()),
+           b_vid.to_str(), b_bounds.inf_str(self.infcx()));
 
+    // Same variable: the easy case.
     if a_vid == b_vid {
-        return Ok(a_t);
+        return Ok(VarResult(a_vid));
     }
 
     // If both A and B have an UB type, then we can just compute the
     // LUB of those types:
     let a_bnd = self.bnd(a_bounds), b_bnd = self.bnd(b_bounds);
     match (a_bnd, b_bnd) {
-      (Some(a_ty), Some(b_ty)) => {
-        match self.infcx().try(|| c_ts(a_ty, b_ty) ) {
-            Ok(t) => return Ok(t),
-            Err(_) => { /*fallthrough */ }
+        (Some(ref a_ty), Some(ref b_ty)) => {
+            match self.infcx().try(|| lattice_dir_op(a_ty, b_ty) ) {
+                Ok(t) => return Ok(ValueResult(t)),
+                Err(_) => { /*fallthrough */ }
+            }
         }
-      }
-      _ => {/*fallthrough*/}
+        _ => {/*fallthrough*/}
     }
 
     // Otherwise, we need to merge A and B into one variable.  We can
     // then use either variable as an upper bound:
-    var_sub_var(self, a_vid, b_vid).then(|| Ok(a_t) )
+    let cf = self.combine_fields();
+    do cf.var_sub_var(vb, a_vid, b_vid).then {
+        Ok(VarResult(a_vid))
+    }
 }
 
-fn lattice_var_and_t<L:lattice_ops combine>(
-    self: &L, a_id: ty::TyVid, b: ty::t,
-    c_ts: fn(ty::t, ty::t) -> cres<ty::t>) -> cres<ty::t> {
-
-    let vb = &self.infcx().ty_var_bindings;
+fn lattice_var_and_t<L:LatticeDir Combine,
+                     V:Copy Eq Vid ToStr,
+                     T:Copy InferStr LatticeValue>(
+    self: &L,
+    vb: &ValsAndBindings<V, Bounds<T>>,
+    +a_id: V,
+    b: &T,
+    lattice_dir_op: LatticeDirOp<T>)
+    -> cres<T>
+{
     let nde_a = self.infcx().get(vb, a_id);
     let a_id = nde_a.root;
-    let a_bounds = nde_a.possible_types;
+    let a_bounds = &nde_a.possible_types;
 
     // The comments in this function are written for LUB, but they
     // apply equally well to GLB if you inverse upper/lower/sub/super/etc.
 
     debug!("%s.lattice_var_and_t(%s=%s <: %s)",
            self.tag(),
-           a_id.to_str(), a_bounds.to_str(self.infcx()),
-           b.to_str(self.infcx()));
+           a_id.to_str(),
+           a_bounds.inf_str(self.infcx()),
+           b.inf_str(self.infcx()));
 
     match self.bnd(a_bounds) {
-      Some(a_bnd) => {
-        // If a has an upper bound, return the LUB(a.ub, b)
-        debug!("bnd=some(%s)", a_bnd.to_str(self.infcx()));
-        return c_ts(a_bnd, b);
-      }
-      None => {
-        // If a does not have an upper bound, make b the upper bound of a
-        // and then return b.
-        debug!("bnd=none");
-        let a_bounds = self.with_bnd(a_bounds, b);
-        do bnds(self, a_bounds.lb, a_bounds.ub).then {
-            self.infcx().set(vb, a_id, root(a_bounds, nde_a.rank));
-            Ok(b)
+        Some(ref a_bnd) => {
+            // If a has an upper bound, return the LUB(a.ub, b)
+            debug!("bnd=some(%s)", a_bnd.inf_str(self.infcx()));
+            lattice_dir_op(a_bnd, b)
+        }
+        None => {
+            // If a does not have an upper bound, make b the upper bound of a
+            // and then return b.
+            debug!("bnd=none");
+            let a_bounds = self.with_bnd(a_bounds, *b);
+            do self.combine_fields().bnds(&a_bounds.lb, &a_bounds.ub).then {
+                self.infcx().set(vb, a_id, Root(a_bounds, nde_a.rank));
+                Ok(*b)
+            }
         }
-      }
     }
 }
 
@@ -171,7 +512,7 @@ fn lattice_var_and_t<L:lattice_ops combine>(
 // Random utility functions used by LUB/GLB when computing LUB/GLB of
 // fn types
 
-fn var_ids<T: combine>(self: &T, isr: isr_alist) -> ~[RegionVid] {
+fn var_ids<T: Combine>(self: &T, isr: isr_alist) -> ~[RegionVid] {
     let mut result = ~[];
     for list::each(isr) |pair| {
         match pair.second() {
diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs
index d478e8d9b92..ac6c4473999 100644
--- a/src/librustc/middle/typeck/infer/lub.rs
+++ b/src/librustc/middle/typeck/infer/lub.rs
@@ -16,7 +16,7 @@ use middle::typeck::infer::combine::*;
 use middle::typeck::infer::glb::Glb;
 use middle::typeck::infer::lattice::*;
 use middle::typeck::infer::sub::Sub;
-use middle::typeck::infer::to_str::ToStr;
+use middle::typeck::infer::to_str::InferStr;
 use middle::typeck::isr_alist;
 use util::ppaux::mt_to_str;
 
@@ -26,15 +26,15 @@ use syntax::ast::{pure_fn, ret_style, return_val, unsafe_fn};
 
 fn macros() { include!("macros.rs"); } // FIXME(#3114): Macro import/export.
 
-enum Lub = combine_fields;  // "subtype", "subregion" etc
+enum Lub = CombineFields;  // least-upper-bound: common supertype
 
 impl Lub {
     fn bot_ty(b: ty::t) -> cres<ty::t> { Ok(b) }
     fn ty_bot(b: ty::t) -> cres<ty::t> { self.bot_ty(b) } // commutative
 }
 
-impl Lub: combine {
-    fn infcx() -> infer_ctxt { self.infcx }
+impl Lub: Combine {
+    fn infcx() -> @InferCtxt { self.infcx }
     fn tag() -> ~str { ~"lub" }
     fn a_is_expected() -> bool { self.a_is_expected }
     fn span() -> span { self.span }
@@ -80,15 +80,6 @@ impl Lub: combine {
         Glb(*self).tys(a, b)
     }
 
-    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
-        match (p1, p2) {
-            (ast::ProtoBare, _) => Ok(p2),
-            (_, ast::ProtoBare) => Ok(p1),
-            _ if p1 == p2 => Ok(p1),
-            _ => Err(ty::terr_proto_mismatch(expected_found(&self, p1, p2)))
-        }
-    }
-
     fn purities(a: purity, b: purity) -> cres<purity> {
         match (a, b) {
           (unsafe_fn, _) | (_, unsafe_fn) => Ok(unsafe_fn),
@@ -112,15 +103,15 @@ impl Lub: combine {
     fn regions(a: ty::Region, b: ty::Region) -> cres<ty::Region> {
         debug!("%s.regions(%?, %?)",
                self.tag(),
-               a.to_str(self.infcx),
-               b.to_str(self.infcx));
+               a.inf_str(self.infcx),
+               b.inf_str(self.infcx));
 
         do indent {
             self.infcx.region_vars.lub_regions(self.span, a, b)
         }
     }
 
-    fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
+    fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
         // Note: this is a subtle algorithm.  For a full explanation,
         // please see the large comment in `region_inference.rs`.
 
@@ -139,18 +130,18 @@ impl Lub: combine {
                 self.span, b);
 
         // Collect constraints.
-        let fn_ty0 = if_ok!(super_fns(&self, &a_with_fresh, &b_with_fresh));
-        debug!("fn_ty0 = %s", fn_ty0.to_str(self.infcx));
+        let sig0 = if_ok!(super_fn_sigs(&self, &a_with_fresh, &b_with_fresh));
+        debug!("sig0 = %s", sig0.inf_str(self.infcx));
 
-        // Generalize the regions appearing in fn_ty0 if possible
+        // Generalize the regions appearing in sig0 if possible
         let new_vars =
             self.infcx.region_vars.vars_created_since_snapshot(snapshot);
-        let fn_ty1 =
+        let sig1 =
             self.infcx.fold_regions_in_sig(
-                &fn_ty0,
+                &sig0,
                 |r, _in_fn| generalize_region(&self, snapshot, new_vars,
                                               a_isr, r));
-        return Ok(move fn_ty1);
+        return Ok(move sig1);
 
         fn generalize_region(self: &Lub,
                              snapshot: uint,
@@ -197,18 +188,22 @@ impl Lub: combine {
         }
     }
 
-    fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
-        super_fn_metas(&self, a, b)
+    fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
+        super_fns(&self, a, b)
     }
 
-    fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
-        super_fn_sigs(&self, a, b)
+    fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
+        super_fn_metas(&self, a, b)
     }
 
     // Traits please (FIXME: #2794):
 
+    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
+        super_protos(&self, p1, p2)
+    }
+
     fn tys(a: ty::t, b: ty::t) -> cres<ty::t> {
-        lattice_tys(&self, a, b)
+        super_lattice_tys(&self, a, b)
     }
 
     fn flds(a: ty::field, b: ty::field) -> cres<ty::field> {
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 51e0a5186e8..40134c76dbd 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -197,29 +197,16 @@ is valid.  This basically corresponds to the block nesting structure:
 the regions for outer block scopes are superregions of those for inner
 block scopes.
 
-## Integral type variables
+## Integral and floating-point type variables
 
 There is a third variety of type variable that we use only for
 inferring the types of unsuffixed integer literals.  Integral type
 variables differ from general-purpose type variables in that there's
 no subtyping relationship among the various integral types, so instead
-of associating each variable with an upper and lower bound, we
-represent the set of possible integral types it can take on with an
-`int_ty_set`, which is a bitvector with one bit for each integral
-type.  Because intersecting these sets with each other is simpler than
-merging bounds, we don't need to do so transactionally as we do for
-general-purpose type variables.
-
-We could conceivably define a subtyping relationship among integral
-types based on their ranges, but we choose not to open that particular
-can of worms.  Our strategy is to treat integral type variables as
-unknown until the typing context constrains them to a unique integral
-type, at which point they take on that type.  If the typing context
-overconstrains the type, it's a type error; if we reach the point at
-which type variables must be resolved and an integral type variable is
-still underconstrained, it defaults to `int` as a last resort.
-
-Floating point types are handled similarly to integral types.
+of associating each variable with an upper and lower bound, we just
+use simple unification.  Each integer variable is associated with at
+most one integer type.  Floating point types are handled similarly to
+integral types.
 
 ## GLB/LUB
 
@@ -261,16 +248,14 @@ section on "Type Combining" below for details.
 
 use core::prelude::*;
 
-use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, vid};
+use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid};
 use middle::ty::{mk_fn, type_is_bot};
 use middle::ty::{ty_int, ty_uint, get, terr_fn, TyVar, IntVar, FloatVar};
 use middle::ty;
-use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_ty};
+use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig};
 use middle::typeck::infer::assignment::Assign;
-use middle::typeck::infer::combine::{combine_fields, eq_tys};
-use middle::typeck::infer::floating::{float_ty_set, float_ty_set_all};
+use middle::typeck::infer::combine::{CombineFields, eq_tys};
 use middle::typeck::infer::glb::Glb;
-use middle::typeck::infer::integral::{int_ty_set, int_ty_set_all};
 use middle::typeck::infer::lub::Lub;
 use middle::typeck::infer::region_inference::{RegionVarBindings};
 use middle::typeck::infer::resolve::{force_all, not_regions};
@@ -280,8 +265,8 @@ use middle::typeck::infer::resolve::{resolve_ivar, resolve_all};
 use middle::typeck::infer::resolve::{resolve_nested_tvar, resolve_rvar};
 use middle::typeck::infer::resolve::{resolver};
 use middle::typeck::infer::sub::Sub;
-use middle::typeck::infer::to_str::ToStr;
-use middle::typeck::infer::unify::{vals_and_bindings, root};
+use middle::typeck::infer::to_str::InferStr;
+use middle::typeck::infer::unify::{ValsAndBindings, Root};
 use middle::typeck::isr_alist;
 use util::common::{indent, indenter};
 use util::ppaux::{bound_region_to_str, ty_to_str, mt_to_str};
@@ -302,7 +287,7 @@ use syntax::ast_util::dummy_sp;
 use syntax::ast_util;
 use syntax::codemap::span;
 
-export infer_ctxt;
+export InferCtxt;
 export new_infer_ctxt;
 export mk_subty, can_mk_subty;
 export mk_subr;
@@ -313,15 +298,12 @@ export force_tvar, force_rvar, force_ivar, force_all;
 export resolve_and_force_all_but_regions, not_regions;
 export resolve_type, resolve_region;
 export resolve_borrowings;
-export methods; // for infer_ctxt
-export unify_methods; // for infer_ctxt
 export cres, fres, fixup_err, fixup_err_to_str;
 export assignment;
 export root, to_str;
 export int_ty_set_all;
 export assignment;
 export combine;
-export floating;
 export glb;
 export integral;
 export lattice;
@@ -333,11 +315,12 @@ export to_str;
 export unify;
 export uok;
 export cyclic_ty, unresolved_ty, region_var_bound_by_region_var;
-export bound, bounds;
+export Bound, Bounds;
 export ures;
 export ares;
 export infer_ctxt;
 export fixup_err;
+export IntVarValue, IntType, UintType;
 
 #[legacy_exports]
 mod assignment;
@@ -346,9 +329,6 @@ mod combine;
 #[legacy_exports]
 mod glb;
 #[legacy_exports]
-mod integral;
-mod floating;
-#[legacy_exports]
 mod lattice;
 #[legacy_exports]
 mod lub;
@@ -363,39 +343,48 @@ mod to_str;
 #[legacy_exports]
 mod unify;
 
-type bound<T:Copy> = Option<T>;
-type bounds<T:Copy> = {lb: bound<T>, ub: bound<T>};
+type Bound<T> = Option<T>;
+type Bounds<T> = {lb: Bound<T>, ub: Bound<T>};
 
 type cres<T> = Result<T,ty::type_err>; // "combine result"
 type ures = cres<()>; // "unify result"
 type fres<T> = Result<T, fixup_err>; // "fixup result"
 type ares = cres<Option<@ty::AutoAdjustment>>; // "assignment result"
 
-enum infer_ctxt = @{
+#[deriving_eq]
+enum IntVarValue {
+    IntType(ast::int_ty),
+    UintType(ast::uint_ty),
+}
+
+struct InferCtxt {
     tcx: ty::ctxt,
 
-    // We instantiate vals_and_bindings with bounds<ty::t> because the
+    // We instantiate ValsAndBindings with bounds<ty::t> because the
     // types that might instantiate a general type variable have an
     // order, represented by its upper and lower bounds.
-    ty_var_bindings: vals_and_bindings<ty::TyVid, bounds<ty::t>>,
+    ty_var_bindings: ValsAndBindings<ty::TyVid, Bounds<ty::t>>,
+
+    // Number of type variables created thus far.
+    mut ty_var_counter: uint,
 
     // The types that might instantiate an integral type variable are
     // represented by an int_ty_set.
-    int_var_bindings: vals_and_bindings<ty::IntVid, int_ty_set>,
+    int_var_bindings: ValsAndBindings<ty::IntVid, Option<IntVarValue>>,
+
+    // Number of integral variables created thus far.
+    mut int_var_counter: uint,
 
     // The types that might instantiate a floating-point type variable are
     // represented by an float_ty_set.
-    float_var_bindings: vals_and_bindings<ty::FloatVid, float_ty_set>,
+    float_var_bindings: ValsAndBindings<ty::FloatVid, Option<ast::float_ty>>,
+
+    // Number of floating-point variables created thus far.
+    mut float_var_counter: uint,
 
     // For region variables.
     region_vars: RegionVarBindings,
-
-    // For keeping track of existing type and region variables.
-    ty_var_counter: @mut uint,
-    int_var_counter: @mut uint,
-    float_var_counter: @mut uint,
-    region_var_counter: @mut uint
-};
+}
 
 enum fixup_err {
     unresolved_int_ty(IntVid),
@@ -418,27 +407,33 @@ fn fixup_err_to_str(f: fixup_err) -> ~str {
     }
 }
 
-fn new_vals_and_bindings<V:Copy, T:Copy>() -> vals_and_bindings<V, T> {
-    vals_and_bindings {
+fn new_ValsAndBindings<V:Copy, T:Copy>() -> ValsAndBindings<V, T> {
+    ValsAndBindings {
         vals: smallintmap::mk(),
         mut bindings: ~[]
     }
 }
 
-fn new_infer_ctxt(tcx: ty::ctxt) -> infer_ctxt {
-    infer_ctxt(@{tcx: tcx,
-                 ty_var_bindings: new_vals_and_bindings(),
-                 int_var_bindings: new_vals_and_bindings(),
-                 float_var_bindings: new_vals_and_bindings(),
-                 region_vars: RegionVarBindings(tcx),
-                 ty_var_counter: @mut 0u,
-                 int_var_counter: @mut 0u,
-                 float_var_counter: @mut 0u,
-                 region_var_counter: @mut 0u})}
-
-fn mk_subty(cx: infer_ctxt, a_is_expected: bool, span: span,
+fn new_infer_ctxt(tcx: ty::ctxt) -> @InferCtxt {
+    @InferCtxt {
+        tcx: tcx,
+
+        ty_var_bindings: new_ValsAndBindings(),
+        ty_var_counter: 0,
+
+        int_var_bindings: new_ValsAndBindings(),
+        int_var_counter: 0,
+
+        float_var_bindings: new_ValsAndBindings(),
+        float_var_counter: 0,
+
+        region_vars: RegionVarBindings(tcx),
+    }
+}
+
+fn mk_subty(cx: @InferCtxt, a_is_expected: bool, span: span,
             a: ty::t, b: ty::t) -> ures {
-    debug!("mk_subty(%s <: %s)", a.to_str(cx), b.to_str(cx));
+    debug!("mk_subty(%s <: %s)", a.inf_str(cx), b.inf_str(cx));
     do indent {
         do cx.commit {
             cx.sub(a_is_expected, span).tys(a, b)
@@ -446,8 +441,8 @@ fn mk_subty(cx: infer_ctxt, a_is_expected: bool, span: span,
     }.to_ures()
 }
 
-fn can_mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
-    debug!("can_mk_subty(%s <: %s)", a.to_str(cx), b.to_str(cx));
+fn can_mk_subty(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures {
+    debug!("can_mk_subty(%s <: %s)", a.inf_str(cx), b.inf_str(cx));
     do indent {
         do cx.probe {
             cx.sub(true, ast_util::dummy_sp()).tys(a, b)
@@ -455,9 +450,9 @@ fn can_mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
     }.to_ures()
 }
 
-fn mk_subr(cx: infer_ctxt, a_is_expected: bool, span: span,
+fn mk_subr(cx: @InferCtxt, a_is_expected: bool, span: span,
            a: ty::Region, b: ty::Region) -> ures {
-    debug!("mk_subr(%s <: %s)", a.to_str(cx), b.to_str(cx));
+    debug!("mk_subr(%s <: %s)", a.inf_str(cx), b.inf_str(cx));
     do indent {
         do cx.commit {
             cx.sub(a_is_expected, span).regions(a, b)
@@ -465,9 +460,9 @@ fn mk_subr(cx: infer_ctxt, a_is_expected: bool, span: span,
     }.to_ures()
 }
 
-fn mk_eqty(cx: infer_ctxt, a_is_expected: bool, span: span,
+fn mk_eqty(cx: @InferCtxt, a_is_expected: bool, span: span,
            a: ty::t, b: ty::t) -> ures {
-    debug!("mk_eqty(%s <: %s)", a.to_str(cx), b.to_str(cx));
+    debug!("mk_eqty(%s <: %s)", a.inf_str(cx), b.inf_str(cx));
     do indent {
         do cx.commit {
             let suber = cx.sub(a_is_expected, span);
@@ -476,9 +471,9 @@ fn mk_eqty(cx: infer_ctxt, a_is_expected: bool, span: span,
     }.to_ures()
 }
 
-fn mk_assignty(cx: infer_ctxt, a_is_expected: bool, span: span,
+fn mk_assignty(cx: @InferCtxt, a_is_expected: bool, span: span,
                a: ty::t, b: ty::t) -> ares {
-    debug!("mk_assignty(%s -> %s)", a.to_str(cx), b.to_str(cx));
+    debug!("mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
     do indent {
         do cx.commit {
             Assign(cx.combine_fields(a_is_expected, span)).tys(a, b)
@@ -486,8 +481,8 @@ fn mk_assignty(cx: infer_ctxt, a_is_expected: bool, span: span,
     }
 }
 
-fn can_mk_assignty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
-    debug!("can_mk_assignty(%s -> %s)", a.to_str(cx), b.to_str(cx));
+fn can_mk_assignty(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures {
+    debug!("can_mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
     do indent {
         do cx.probe {
             let span = ast_util::dummy_sp();
@@ -497,18 +492,18 @@ fn can_mk_assignty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
 }
 
 // See comment on the type `resolve_state` below
-fn resolve_type(cx: infer_ctxt, a: ty::t, modes: uint)
+fn resolve_type(cx: @InferCtxt, a: ty::t, modes: uint)
     -> fres<ty::t> {
     resolver(cx, modes).resolve_type_chk(a)
 }
 
-fn resolve_region(cx: infer_ctxt, r: ty::Region, modes: uint)
+fn resolve_region(cx: @InferCtxt, r: ty::Region, modes: uint)
     -> fres<ty::Region> {
     resolver(cx, modes).resolve_region_chk(r)
 }
 
 /*
-fn resolve_borrowings(cx: infer_ctxt) {
+fn resolve_borrowings(cx: @InferCtxt) {
     for cx.borrowings.each |item| {
         match resolve_region(cx, item.scope, resolve_all|force_all) {
           Ok(region) => {
@@ -574,9 +569,10 @@ pub fn uok() -> ures {
     Ok(())
 }
 
-fn rollback_to<V:Copy vid, T:Copy>(
-    vb: &vals_and_bindings<V, T>, len: uint) {
-
+fn rollback_to<V:Copy Vid, T:Copy>(
+    vb: &ValsAndBindings<V, T>,
+    len: uint)
+{
     while vb.bindings.len() != len {
         let (vid, old_v) = vb.bindings.pop();
         vb.vals.insert(vid.to_uint(), old_v);
@@ -589,12 +585,12 @@ struct Snapshot {
     region_vars_snapshot: uint,
 }
 
-impl infer_ctxt {
+impl @InferCtxt {
     fn combine_fields(a_is_expected: bool,
-                      span: span) -> combine_fields {
-        combine_fields {infcx: self,
-                        a_is_expected: a_is_expected,
-                        span: span}
+                      span: span) -> CombineFields {
+        CombineFields {infcx: self,
+                       a_is_expected: a_is_expected,
+                       span: span}
     }
 
     fn sub(a_is_expected: bool, span: span) -> Sub {
@@ -624,8 +620,7 @@ impl infer_ctxt {
         //rollback_to(&self.int_var_bindings,
         //            snapshot.int_var_bindings_len);
 
-        self.region_vars.rollback_to(
-            snapshot.region_vars_snapshot);
+        self.region_vars.rollback_to(snapshot.region_vars_snapshot);
     }
 
     /// Execute `f` and commit the bindings if successful
@@ -669,12 +664,12 @@ impl infer_ctxt {
     }
 }
 
-impl infer_ctxt {
+impl @InferCtxt {
     fn next_ty_var_id() -> TyVid {
-        let id = *self.ty_var_counter;
-        *self.ty_var_counter += 1u;
+        let id = self.ty_var_counter;
+        self.ty_var_counter += 1;
         self.ty_var_bindings.vals.insert(id,
-                                         root({lb: None, ub: None}, 0u));
+                                         Root({lb: None, ub: None}, 0u));
         return TyVid(id);
     }
 
@@ -687,11 +682,10 @@ impl infer_ctxt {
     }
 
     fn next_int_var_id() -> IntVid {
-        let id = *self.int_var_counter;
-        *self.int_var_counter += 1u;
+        let id = self.int_var_counter;
+        self.int_var_counter += 1;
 
-        self.int_var_bindings.vals.insert(id,
-                              root(int_ty_set_all(), 0u));
+        self.int_var_bindings.vals.insert(id, Root(None, 0));
         return IntVid(id);
     }
 
@@ -700,10 +694,10 @@ impl infer_ctxt {
     }
 
     fn next_float_var_id() -> FloatVid {
-        let id = *self.float_var_counter;
-        *self.float_var_counter += 1;
+        let id = self.float_var_counter;
+        self.float_var_counter += 1;
 
-        self.float_var_bindings.vals.insert(id, root(float_ty_set_all(), 0));
+        self.float_var_bindings.vals.insert(id, Root(None, 0));
         return FloatVid(id);
     }
 
@@ -795,10 +789,10 @@ impl infer_ctxt {
 
     fn replace_bound_regions_with_fresh_regions(
         &self, span: span,
-        fty: &ty::FnTy) -> (ty::FnTy, isr_alist)
+        fsig: &ty::FnSig) -> (ty::FnSig, isr_alist)
     {
-        let {fn_ty: fn_ty, isr: isr, _} =
-            replace_bound_regions_in_fn_ty(self.tcx, @Nil, None, fty, |br| {
+        let {fn_sig: fn_sig, isr: isr, _} =
+            replace_bound_regions_in_fn_sig(self.tcx, @Nil, None, fsig, |br| {
                 // N.B.: The name of the bound region doesn't have anything to
                 // do with the region variable that's created for it.  The
                 // only thing we're doing with `br` here is using it in the
@@ -809,18 +803,17 @@ impl infer_ctxt {
                        rvar);
                 rvar
             });
-        (fn_ty, isr)
+        (fn_sig, isr)
     }
 
     fn fold_regions_in_sig(
         &self,
-        fn_ty: &ty::FnTy,
-        fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnTy
+        fn_sig: &ty::FnSig,
+        fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnSig
     {
-        let sig = do ty::fold_sig(&fn_ty.sig) |t| {
+        do ty::fold_sig(fn_sig) |t| {
             ty::fold_regions(self.tcx, t, fldr)
-        };
-        ty::FnTyBase {meta: fn_ty.meta, sig: sig}
+        }
     }
 
 }
diff --git a/src/librustc/middle/typeck/infer/region_inference.rs b/src/librustc/middle/typeck/infer/region_inference.rs
index 0d9c90e454c..54854bed65e 100644
--- a/src/librustc/middle/typeck/infer/region_inference.rs
+++ b/src/librustc/middle/typeck/infer/region_inference.rs
@@ -544,10 +544,11 @@ use core::prelude::*;
 use middle::region::is_subregion_of;
 use middle::region;
 use middle::ty;
-use middle::ty::{Region, RegionVid, br_fresh, re_bound, re_free, re_infer};
-use middle::ty::{re_scope, re_static, ReVar, ReSkolemized};
+use middle::ty::{Region, RegionVid, re_static, re_infer, re_free, re_bound};
+use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh};
+use middle::typeck::infer::to_str::InferStr;
 use middle::typeck::infer::cres;
-use middle::typeck::infer::to_str::ToStr;
+use syntax::codemap;
 use util::common::indenter;
 use util::ppaux::note_and_explain_region;
 
diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs
index 68e589cab27..23be3b20827 100644
--- a/src/librustc/middle/typeck/infer/resolve.rs
+++ b/src/librustc/middle/typeck/infer/resolve.rs
@@ -51,60 +51,61 @@ use core::prelude::*;
 use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid};
 use middle::ty::{type_is_bot};
 use middle::ty;
-use middle::typeck::infer::{cyclic_ty, fixup_err, fres, infer_ctxt};
+use middle::typeck::infer::{cyclic_ty, fixup_err, fres, InferCtxt};
 use middle::typeck::infer::{region_var_bound_by_region_var, unresolved_ty};
-use middle::typeck::infer::floating::*;
-use middle::typeck::infer::floating;
-use middle::typeck::infer::integral::*;
-use middle::typeck::infer::integral;
-use middle::typeck::infer::to_str::ToStr;
-use middle::typeck::infer::unify::root;
-use util::common::indent;
+use middle::typeck::infer::{IntType, UintType};
+use middle::typeck::infer::to_str::InferStr;
+use middle::typeck::infer::unify::Root;
+use util::common::{indent, indenter};
 use util::ppaux::ty_to_str;
 
+use syntax::ast;
+
 use core::uint;
 use core::vec;
 
-const resolve_nested_tvar: uint = 0b00000001;
-const resolve_rvar: uint        = 0b00000010;
-const resolve_ivar: uint        = 0b00000100;
-const resolve_fvar: uint        = 0b00001000;
-const resolve_all: uint         = 0b00001111;
-const force_tvar: uint          = 0b00010000;
-const force_rvar: uint          = 0b00100000;
-const force_ivar: uint          = 0b01000000;
-const force_fvar: uint          = 0b11000000;
-const force_all: uint           = 0b11110000;
+const resolve_nested_tvar: uint = 0b0000000001;
+const resolve_rvar: uint        = 0b0000000010;
+const resolve_ivar: uint        = 0b0000000100;
+const resolve_fvar: uint        = 0b0000001000;
+const resolve_fnvar: uint       = 0b0000010000;
+const resolve_all: uint         = 0b0000011111;
+const force_tvar: uint          = 0b0000100000;
+const force_rvar: uint          = 0b0001000000;
+const force_ivar: uint          = 0b0010000000;
+const force_fvar: uint          = 0b0100000000;
+const force_fnvar: uint         = 0b1000000000;
+const force_all: uint           = 0b1111100000;
 
 const not_regions: uint         = !(force_rvar | resolve_rvar);
 
 const resolve_and_force_all_but_regions: uint =
     (resolve_all | force_all) & not_regions;
 
-type resolve_state_ = {
-    infcx: infer_ctxt,
+struct ResolveState {
+    infcx: @InferCtxt,
     modes: uint,
     mut err: Option<fixup_err>,
-    mut v_seen: ~[TyVid]
-};
-
-enum resolve_state {
-    resolve_state_(@resolve_state_)
+    mut v_seen: ~[TyVid],
+    mut type_depth: uint
 }
 
-fn resolver(infcx: infer_ctxt, modes: uint) -> resolve_state {
-    resolve_state_(@{infcx: infcx,
-                     modes: modes,
-                     mut err: None,
-                     mut v_seen: ~[]})
+fn resolver(infcx: @InferCtxt, modes: uint) -> ResolveState {
+    ResolveState {
+        infcx: infcx,
+        modes: modes,
+        err: None,
+        v_seen: ~[],
+        type_depth: 0
+    }
 }
 
-impl resolve_state {
-    fn should(mode: uint) -> bool {
+impl ResolveState {
+    fn should(&self, mode: uint) -> bool {
         (self.modes & mode) == mode
     }
 
-    fn resolve_type_chk(typ: ty::t) -> fres<ty::t> {
+    fn resolve_type_chk(&self, typ: ty::t) -> fres<ty::t> {
         self.err = None;
 
         debug!("Resolving %s (modes=%x)",
@@ -129,7 +130,7 @@ impl resolve_state {
         }
     }
 
-    fn resolve_region_chk(orig: ty::Region) -> fres<ty::Region> {
+    fn resolve_region_chk(&self, orig: ty::Region) -> fres<ty::Region> {
         self.err = None;
         let resolved = indent(|| self.resolve_region(orig) );
         match self.err {
@@ -138,63 +139,64 @@ impl resolve_state {
         }
     }
 
-    fn resolve_type(typ: ty::t) -> ty::t {
-        debug!("resolve_type(%s)", typ.to_str(self.infcx));
-        indent(fn&() -> ty::t {
-            if !ty::type_needs_infer(typ) { return typ; }
+    fn resolve_type(&self, typ: ty::t) -> ty::t {
+        debug!("resolve_type(%s)", typ.inf_str(self.infcx));
+        let _i = indenter();
+
+        if !ty::type_needs_infer(typ) {
+            return typ;
+        }
+
+        if self.type_depth > 0 && !self.should(resolve_nested_tvar) {
+            return typ;
+        }
 
-            match copy ty::get(typ).sty {
-              ty::ty_infer(TyVar(vid)) => {
+        match /*bad*/ copy ty::get(typ).sty {
+            ty::ty_infer(TyVar(vid)) => {
                 self.resolve_ty_var(vid)
-              }
-              ty::ty_infer(IntVar(vid)) => {
+            }
+            ty::ty_infer(IntVar(vid)) => {
                 self.resolve_int_var(vid)
-              }
-              ty::ty_infer(FloatVar(vid)) => {
+            }
+            ty::ty_infer(FloatVar(vid)) => {
                 self.resolve_float_var(vid)
-              }
-              _ => {
-                if !self.should(resolve_rvar) &&
-                    !self.should(resolve_nested_tvar) {
-                    // shortcircuit for efficiency
+            }
+            _ => {
+                if self.modes & resolve_all == 0 {
+                    // if we are only resolving top-level type
+                    // variables, and this is not a top-level type
+                    // variable, then shortcircuit for efficiency
                     typ
                 } else {
-                    ty::fold_regions_and_ty(
+                    self.type_depth += 1;
+                    let result = ty::fold_regions_and_ty(
                         self.infcx.tcx, typ,
                         |r| self.resolve_region(r),
-                        |t| self.resolve_nested_tvar(t),
-                        |t| self.resolve_nested_tvar(t))
+                        |t| self.resolve_type(t),
+                        |t| self.resolve_type(t));
+                    self.type_depth -= 1;
+                    result
                 }
-              }
             }
-        })
-    }
-
-    fn resolve_nested_tvar(typ: ty::t) -> ty::t {
-        debug!("Resolve_if_deep(%s)", typ.to_str(self.infcx));
-        if !self.should(resolve_nested_tvar) {
-            typ
-        } else {
-            self.resolve_type(typ)
         }
     }
 
-    fn resolve_region(orig: ty::Region) -> ty::Region {
-        debug!("Resolve_region(%s)", orig.to_str(self.infcx));
+    fn resolve_region(&self, orig: ty::Region) -> ty::Region {
+        debug!("Resolve_region(%s)", orig.inf_str(self.infcx));
         match orig {
           ty::re_infer(ty::ReVar(rid)) => self.resolve_region_var(rid),
           _ => orig
         }
     }
 
-    fn resolve_region_var(rid: RegionVid) -> ty::Region {
+    fn resolve_region_var(&self, rid: RegionVid) -> ty::Region {
         if !self.should(resolve_rvar) {
             return ty::re_infer(ty::ReVar(rid));
         }
         self.infcx.region_vars.resolve_var(rid)
     }
 
-    fn assert_not_rvar(rid: RegionVid, r: ty::Region) {
+    fn assert_not_rvar(&self, rid: RegionVid, r: ty::Region) {
         match r {
           ty::re_infer(ty::ReVar(rid2)) => {
             self.err = Some(region_var_bound_by_region_var(rid, rid2));
@@ -203,7 +205,7 @@ impl resolve_state {
         }
     }
 
-    fn resolve_ty_var(vid: TyVid) -> ty::t {
+    fn resolve_ty_var(&self, vid: TyVid) -> ty::t {
         if vec::contains(self.v_seen, &vid) {
             self.err = Some(cyclic_ty(vid));
             return ty::mk_var(self.infcx.tcx, vid);
@@ -236,27 +238,22 @@ impl resolve_state {
         }
     }
 
-    fn resolve_int_var(vid: IntVid) -> ty::t {
+    fn resolve_int_var(&self, vid: IntVid) -> ty::t {
         if !self.should(resolve_ivar) {
             return ty::mk_int_var(self.infcx.tcx, vid);
         }
 
-        let nde = self.infcx.get(&self.infcx.int_var_bindings, vid);
-        let pt = nde.possible_types;
-
-        // If there's only one type in the set of possible types, then
-        // that's the answer.
-        match integral::single_type_contained_in(self.infcx.tcx, pt) {
-          Some(t) => t,
+        let node = self.infcx.get(&self.infcx.int_var_bindings, vid);
+        match node.possible_types {
+          Some(IntType(t)) => ty::mk_mach_int(self.infcx.tcx, t),
+          Some(UintType(t)) => ty::mk_mach_uint(self.infcx.tcx, t),
           None => {
             if self.should(force_ivar) {
                 // As a last resort, default to int.
                 let ty = ty::mk_int(self.infcx.tcx);
                 self.infcx.set(
                     &self.infcx.int_var_bindings, vid,
-                    root(convert_integral_ty_to_int_ty_set(self.infcx.tcx,
-                                                           ty),
-                        nde.rank));
+                    Root(Some(IntType(ast::ty_i)), node.rank));
                 ty
             } else {
                 ty::mk_int_var(self.infcx.tcx, vid)
@@ -265,18 +262,14 @@ impl resolve_state {
         }
     }
 
-    fn resolve_float_var(vid: FloatVid) -> ty::t {
+    fn resolve_float_var(&self, vid: FloatVid) -> ty::t {
         if !self.should(resolve_fvar) {
             return ty::mk_float_var(self.infcx.tcx, vid);
         }
 
-        let nde = self.infcx.get(&self.infcx.float_var_bindings, vid);
-        let pt = nde.possible_types;
-
-        // If there's only one type in the set of possible types, then
-        // that's the answer.
-        match floating::single_type_contained_in(self.infcx.tcx, pt) {
-          Some(t) => t,
+        let node = self.infcx.get(&self.infcx.float_var_bindings, vid);
+        match node.possible_types {
+          Some(t) => ty::mk_mach_float(self.infcx.tcx, t),
           None => {
             if self.should(force_fvar) {
                 // As a last resort, default to float.
@@ -284,10 +277,7 @@ impl resolve_state {
                 self.infcx.set(
                     &self.infcx.float_var_bindings,
                     vid,
-                    root(
-                        convert_floating_point_ty_to_float_ty_set(
-                            self.infcx.tcx, ty),
-                        nde.rank));
+                    Root(Some(ast::ty_f), node.rank));
                 ty
             } else {
                 ty::mk_float_var(self.infcx.tcx, vid)
diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs
index 79405e955f5..aa6721fb229 100644
--- a/src/librustc/middle/typeck/infer/sub.rs
+++ b/src/librustc/middle/typeck/infer/sub.rs
@@ -11,13 +11,13 @@
 use core::prelude::*;
 
 use middle::ty;
-use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_ty;
+use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
 use middle::typeck::infer::combine::*;
 use middle::typeck::infer::cres;
 use middle::typeck::infer::glb::Glb;
-use middle::typeck::infer::infer_ctxt;
+use middle::typeck::infer::InferCtxt;
 use middle::typeck::infer::lub::Lub;
-use middle::typeck::infer::to_str::ToStr;
+use middle::typeck::infer::to_str::InferStr;
 use middle::typeck::infer::unify::*;
 use util::ppaux::bound_region_to_str;
 
@@ -27,10 +27,10 @@ use syntax::ast::{m_const, purity, ret_style};
 
 fn macros() { include!("macros.rs"); } // FIXME(#3114): Macro import/export.
 
-enum Sub = combine_fields;  // "subtype", "subregion" etc
+enum Sub = CombineFields;  // "subtype", "subregion" etc
 
-impl Sub: combine {
-    fn infcx() -> infer_ctxt { self.infcx }
+impl Sub: Combine {
+    fn infcx() -> @InferCtxt { self.infcx }
     fn tag() -> ~str { ~"sub" }
     fn a_is_expected() -> bool { self.a_is_expected }
     fn span() -> span { self.span }
@@ -40,14 +40,14 @@ impl Sub: combine {
     fn glb() -> Glb { Glb(*self) }
 
     fn contratys(a: ty::t, b: ty::t) -> cres<ty::t> {
-        let opp = combine_fields {
+        let opp = CombineFields {
             a_is_expected: !self.a_is_expected,.. *self
         };
         Sub(opp).tys(b, a)
     }
 
     fn contraregions(a: ty::Region, b: ty::Region) -> cres<ty::Region> {
-        let opp = combine_fields {
+        let opp = CombineFields {
             a_is_expected: !self.a_is_expected,.. *self
         };
         Sub(opp).regions(b, a)
@@ -56,8 +56,8 @@ impl Sub: combine {
     fn regions(a: ty::Region, b: ty::Region) -> cres<ty::Region> {
         debug!("%s.regions(%s, %s)",
                self.tag(),
-               a.to_str(self.infcx),
-               b.to_str(self.infcx));
+               a.inf_str(self.infcx),
+               b.inf_str(self.infcx));
         do indent {
             match self.infcx.region_vars.make_subregion(self.span, a, b) {
               Ok(()) => Ok(a),
@@ -67,7 +67,7 @@ impl Sub: combine {
     }
 
     fn mts(a: ty::mt, b: ty::mt) -> cres<ty::mt> {
-        debug!("mts(%s <: %s)", a.to_str(self.infcx), b.to_str(self.infcx));
+        debug!("mts(%s <: %s)", a.inf_str(self.infcx), b.inf_str(self.infcx));
 
         if a.mutbl != b.mutbl && b.mutbl != m_const {
             return Err(ty::terr_mutability);
@@ -86,14 +86,6 @@ impl Sub: combine {
         }
     }
 
-    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
-        match (p1, p2) {
-            (ast::ProtoBare, _) => Ok(p1),
-            _ if p1 == p2 => Ok(p1),
-            _ => Err(ty::terr_proto_mismatch(expected_found(&self, p1, p2)))
-        }
-    }
-
     fn purities(a: purity, b: purity) -> cres<purity> {
         self.lub().purities(a, b).compare(b, || {
             ty::terr_purity_mismatch(expected_found(&self, a, b))
@@ -108,34 +100,47 @@ impl Sub: combine {
 
     fn tys(a: ty::t, b: ty::t) -> cres<ty::t> {
         debug!("%s.tys(%s, %s)", self.tag(),
-               a.to_str(self.infcx), b.to_str(self.infcx));
+               a.inf_str(self.infcx), b.inf_str(self.infcx));
         if a == b { return Ok(a); }
         do indent {
             match (ty::get(a).sty, ty::get(b).sty) {
-              (ty::ty_bot, _) => {
-                Ok(a)
-              }
-              (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => {
-                var_sub_var(&self, a_id, b_id).then(|| Ok(a) )
-              }
-              (ty::ty_infer(TyVar(a_id)), _) => {
-                var_sub_t(&self, a_id, b).then(|| Ok(a) )
-              }
-              (_, ty::ty_infer(TyVar(b_id))) => {
-                t_sub_var(&self, a, b_id).then(|| Ok(a) )
-              }
-              (_, ty::ty_bot) => {
-                Err(ty::terr_sorts(expected_found(&self, a, b)))
-              }
-              _ => {
-                super_tys(&self, a, b)
-              }
+                (ty::ty_bot, _) => {
+                    Ok(a)
+                }
+
+                (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => {
+                    do self.var_sub_var(&self.infcx.ty_var_bindings,
+                                        a_id, b_id).then {
+                        Ok(a)
+                    }
+                }
+                (ty::ty_infer(TyVar(a_id)), _) => {
+                    do self.var_sub_t(&self.infcx.ty_var_bindings,
+                                      a_id, b).then {
+                        Ok(a)
+                    }
+                }
+                (_, ty::ty_infer(TyVar(b_id))) => {
+                    do self.t_sub_var(&self.infcx.ty_var_bindings,
+                                      a, b_id).then {
+                        Ok(a)
+                    }
+                }
+
+                (_, ty::ty_bot) => {
+                    Err(ty::terr_sorts(expected_found(&self, a, b)))
+                }
+
+                _ => {
+                    super_tys(&self, a, b)
+                }
             }
         }
     }
 
-    fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
-        debug!("fns(a=%s, b=%s)", a.to_str(self.infcx), b.to_str(self.infcx));
+    fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
+        debug!("fn_sigs(a=%s, b=%s)",
+               a.inf_str(self.infcx), b.inf_str(self.infcx));
         let _indenter = indenter();
 
         // Rather than checking the subtype relationship between `a` and `b`
@@ -153,14 +158,14 @@ impl Sub: combine {
 
         // First, we instantiate each bound region in the subtype with a fresh
         // region variable.
-        let (a_fn_ty, _) =
+        let (a_sig, _) =
             self.infcx.replace_bound_regions_with_fresh_regions(
                 self.span, a);
 
         // Second, we instantiate each bound region in the supertype with a
         // fresh concrete region.
-        let {fn_ty: b_fn_ty, isr: skol_isr, _} = {
-            do replace_bound_regions_in_fn_ty(self.infcx.tcx, @Nil,
+        let {fn_sig: b_sig, isr: skol_isr, _} = {
+            do replace_bound_regions_in_fn_sig(self.infcx.tcx, @Nil,
                                               None, b) |br| {
                 let skol = self.infcx.region_vars.new_skolemized(br);
                 debug!("Bound region %s skolemized to %?",
@@ -170,11 +175,11 @@ impl Sub: combine {
             }
         };
 
-        debug!("a_fn_ty=%s", a_fn_ty.to_str(self.infcx));
-        debug!("b_fn_ty=%s", b_fn_ty.to_str(self.infcx));
+        debug!("a_sig=%s", a_sig.inf_str(self.infcx));
+        debug!("b_sig=%s", b_sig.inf_str(self.infcx));
 
         // Compare types now that bound regions have been replaced.
-        let fn_ty = if_ok!(super_fns(&self, &a_fn_ty, &b_fn_ty));
+        let sig = if_ok!(super_fn_sigs(&self, &a_sig, &b_sig));
 
         // Presuming type comparison succeeds, we need to check
         // that the skolemized regions do not "leak".
@@ -206,21 +211,25 @@ impl Sub: combine {
             }
         }
 
-        return Ok(fn_ty)
+        return Ok(sig);
     }
 
     // Traits please (FIXME: #2794):
 
+    fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
+        super_protos(&self, p1, p2)
+    }
+
     fn flds(a: ty::field, b: ty::field) -> cres<ty::field> {
         super_flds(&self, a, b)
     }
 
-    fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
-        super_fn_metas(&self, a, b)
+    fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
+        super_fns(&self, a, b)
     }
 
-    fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
-        super_fn_sigs(&self, a, b)
+    fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
+        super_fn_metas(&self, a, b)
     }
 
     fn vstores(vk: ty::terr_vstore_kind,
diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs
index 0a1647eb09a..42f516fe6d8 100644
--- a/src/librustc/middle/typeck/infer/to_str.rs
+++ b/src/librustc/middle/typeck/infer/to_str.rs
@@ -10,86 +10,101 @@
 
 use core::prelude::*;
 
-use middle::ty::vid;
+use middle::ty::{FnMeta, FnTyBase, FnSig, FnVid, Vid};
 use middle::ty;
-use middle::typeck::infer::{bound, bounds};
-use middle::typeck::infer::floating::float_ty_set;
-use middle::typeck::infer::infer_ctxt;
-use middle::typeck::infer::integral::int_ty_set;
-use middle::typeck::infer::unify::{redirect, root, var_value};
+use middle::typeck::infer::{Bound, Bounds};
+use middle::typeck::infer::{IntVarValue, IntType, UintType};
+use middle::typeck::infer::InferCtxt;
+use middle::typeck::infer::unify::{Redirect, Root, VarValue};
 use util::ppaux::{mt_to_str, ty_to_str};
 use util::ppaux;
 
+use syntax::{ast, ast_util};
+
 use core::uint;
+use core::str;
 
-trait ToStr {
-    fn to_str(cx: infer_ctxt) -> ~str;
+pub trait InferStr {
+    fn inf_str(cx: @InferCtxt) -> ~str;
 }
 
-impl ty::t: ToStr {
-    fn to_str(cx: infer_ctxt) -> ~str {
+impl ty::t : InferStr {
+    fn inf_str(cx: @InferCtxt) -> ~str {
         ty_to_str(cx.tcx, self)
     }
 }
 
-impl ty::mt: ToStr {
-    fn to_str(cx: infer_ctxt) -> ~str {
-        mt_to_str(cx.tcx, self)
+impl FnMeta : InferStr {
+    fn inf_str(_cx: @InferCtxt) -> ~str {
+        fmt!("%?", self)
     }
 }
 
-impl ty::Region: ToStr {
-    fn to_str(cx: infer_ctxt) -> ~str {
-        ppaux::region_to_str(cx.tcx, self)
+impl FnSig : InferStr {
+    fn inf_str(cx: @InferCtxt) -> ~str {
+        fmt!("(%s) -> %s",
+             str::connect(self.inputs.map(|a| a.ty.inf_str(cx)), ", "),
+             self.output.inf_str(cx))
     }
 }
 
-impl ty::FnTy: ToStr {
-    fn to_str(cx: infer_ctxt) -> ~str {
-        ty::mk_fn(cx.tcx, self).to_str(cx)
+impl<M:InferStr> FnTyBase<M> : InferStr {
+    fn inf_str(cx: @InferCtxt) -> ~str {
+        fmt!("%s%s", self.meta.inf_str(cx), self.sig.inf_str(cx))
     }
 }
 
-impl<V:Copy ToStr> bound<V>: ToStr {
-    fn to_str(cx: infer_ctxt) -> ~str {
+impl ty::mt : InferStr {
+    fn inf_str(cx: @InferCtxt) -> ~str {
+        mt_to_str(cx.tcx, self)
+    }
+}
+
+impl ty::Region : InferStr {
+    fn inf_str(_cx: @InferCtxt) -> ~str {
+        fmt!("%?", self)
+    }
+}
+
+impl<V:InferStr> Bound<V> : InferStr {
+    fn inf_str(cx: @InferCtxt) -> ~str {
         match self {
-          Some(ref v) => (*v).to_str(cx),
+          Some(ref v) => v.inf_str(cx),
           None => ~"none"
         }
     }
 }
 
-impl<T:Copy ToStr> bounds<T>: ToStr {
-    fn to_str(cx: infer_ctxt) -> ~str {
+impl<T:InferStr> Bounds<T> : InferStr {
+    fn inf_str(cx: @InferCtxt) -> ~str {
         fmt!("{%s <: %s}",
-             self.lb.to_str(cx),
-             self.ub.to_str(cx))
+             self.lb.inf_str(cx),
+             self.ub.inf_str(cx))
     }
 }
 
-impl int_ty_set: ToStr {
-    fn to_str(_cx: infer_ctxt) -> ~str {
+impl<V:Vid ToStr, T:InferStr> VarValue<V, T> : InferStr {
+    fn inf_str(cx: @InferCtxt) -> ~str {
         match self {
-          int_ty_set(v) => uint::to_str(v, 10u)
+          Redirect(ref vid) => fmt!("Redirect(%s)", vid.to_str()),
+          Root(ref pt, rk) => fmt!("Root(%s, %s)", pt.inf_str(cx),
+                               uint::to_str(rk, 10u))
         }
     }
 }
 
-impl float_ty_set: ToStr {
-    fn to_str(_cx: infer_ctxt) -> ~str {
+impl IntVarValue : InferStr {
+    fn inf_str(_cx: @InferCtxt) -> ~str {
         match self {
-          float_ty_set(v) => uint::to_str(v, 10u)
+            IntType(t) => ast_util::int_ty_to_str(t),
+            UintType(t) => ast_util::uint_ty_to_str(t)
         }
     }
 }
 
-impl<V:Copy vid, T:Copy ToStr> var_value<V, T>: ToStr {
-    fn to_str(cx: infer_ctxt) -> ~str {
-        match self {
-          redirect(ref vid) => fmt!("redirect(%s)", (*vid).to_str()),
-          root(ref pt, rk) => fmt!("root(%s, %s)", (*pt).to_str(cx),
-                               uint::to_str(rk, 10u))
-        }
+impl ast::float_ty : InferStr {
+    fn inf_str(_cx: @InferCtxt) -> ~str {
+        ast_util::float_ty_to_str(self)
     }
 }
 
diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs
index 633ff706a26..77bd46eea2d 100644
--- a/src/librustc/middle/typeck/infer/unify.rs
+++ b/src/librustc/middle/typeck/infer/unify.rs
@@ -10,40 +10,45 @@
 
 use core::prelude::*;
 
-use middle::ty::vid;
+use middle::ty::Vid;
 use middle::ty;
-use middle::typeck::infer::{bound, bounds, cres, uok, ures};
-use middle::typeck::infer::combine::combine;
-use middle::typeck::infer::floating::*;
-use middle::typeck::infer::floating;
-use middle::typeck::infer::infer_ctxt;
-use middle::typeck::infer::integral::*;
-use middle::typeck::infer::integral;
-use middle::typeck::infer::to_str::ToStr;
+use middle::typeck::infer::{Bound, Bounds, cres, uok, ures};
+use middle::typeck::infer::combine::Combine;
+use middle::typeck::infer::InferCtxt;
+use middle::typeck::infer::to_str::InferStr;
 use util::common::{indent, indenter};
 
 use core::result;
 use std::smallintmap::SmallIntMap;
 
-enum var_value<V:Copy, T:Copy> {
-    redirect(V),
-    root(T, uint),
+enum VarValue<V, T> {
+    Redirect(V),
+    Root(T, uint),
 }
 
-struct vals_and_bindings<V:Copy, T:Copy> {
-    vals: SmallIntMap<var_value<V, T>>,
-    mut bindings: ~[(V, var_value<V, T>)],
+struct ValsAndBindings<V:Copy, T:Copy> {
+    vals: SmallIntMap<VarValue<V, T>>,
+    mut bindings: ~[(V, VarValue<V, T>)],
 }
 
-struct node<V:Copy, T:Copy> {
+struct Node<V:Copy, T:Copy> {
     root: V,
     possible_types: T,
     rank: uint,
 }
 
-impl infer_ctxt {
-    fn get<V:Copy vid Eq, T:Copy>(
-        vb: &vals_and_bindings<V, T>, vid: V) -> node<V, T> {
+impl @InferCtxt {
+    fn get<V:Copy Eq Vid, T:Copy>(
+        vb: &ValsAndBindings<V, T>,
+        vid: V)
+        -> Node<V, T>
+    {
+        /*!
+         *
+         * Find the root node for `vid`. This uses the standard
+         * union-find algorithm with path compression:
+         * http://en.wikipedia.org/wiki/Disjoint-set_data_structure
+         */
 
         let vid_u = vid.to_uint();
         match vb.vals.find(vid_u) {
@@ -52,435 +57,141 @@ impl infer_ctxt {
           }
           Some(ref var_val) => {
             match (*var_val) {
-              redirect(ref vid) => {
+              Redirect(ref vid) => {
                 let node = self.get(vb, (*vid));
                 if node.root.ne(vid) {
                     // Path compression
-                    vb.vals.insert((*vid).to_uint(), redirect(node.root));
+                    vb.vals.insert(vid.to_uint(), Redirect(node.root));
                 }
                 node
               }
-              root(ref pt, rk) => {
-                node {root: vid, possible_types: (*pt), rank: rk}
+              Root(ref pt, rk) => {
+                Node {root: vid, possible_types: *pt, rank: rk}
               }
             }
           }
         }
     }
 
-    fn set<V:Copy vid, T:Copy ToStr>(
-        vb: &vals_and_bindings<V, T>, vid: V,
-        +new_v: var_value<V, T>) {
+    fn set<V:Copy Vid ToStr, T:Copy InferStr>(
+        vb: &ValsAndBindings<V, T>,
+        vid: V,
+        +new_v: VarValue<V, T>)
+    {
+        /*!
+         *
+         * Sets the value for `vid` to `new_v`.  `vid` MUST be a root node!
+         */
 
         let old_v = vb.vals.get(vid.to_uint());
         vb.bindings.push((vid, old_v));
         vb.vals.insert(vid.to_uint(), new_v);
 
         debug!("Updating variable %s from %s to %s",
-               vid.to_str(), old_v.to_str(self), new_v.to_str(self));
+               vid.to_str(), old_v.inf_str(self), new_v.inf_str(self));
     }
-}
-
-// Combines the two bounds into a more general bound.
-fn merge_bnd<C: combine>(
-    self: &C, a: bound<ty::t>, b: bound<ty::t>,
-    merge_op: fn(ty::t,ty::t) -> cres<ty::t>) -> cres<bound<ty::t>> {
-
-    debug!("merge_bnd(%s,%s)",
-           a.to_str(self.infcx()),
-           b.to_str(self.infcx()));
-    let _r = indenter();
-
-    match (a, b) {
-      (None, None) => Ok(None),
-      (Some(_), None) => Ok(a),
-      (None, Some(_)) => Ok(b),
-      (Some(v_a), Some(v_b)) => {
-        do merge_op(v_a, v_b).chain |v| {
-            Ok(Some(v))
-        }
-      }
-    }
-}
-
-fn merge_bnds<C: combine>(
-    self: &C, a: bounds<ty::t>, b: bounds<ty::t>,
-    lub: fn(ty::t,ty::t) -> cres<ty::t>,
-    glb: fn(ty::t,ty::t) -> cres<ty::t>) -> cres<bounds<ty::t>> {
-
-    let _r = indenter();
-    do merge_bnd(self, a.ub, b.ub, glb).chain |ub| {
-        debug!("glb of ubs %s and %s is %s",
-               a.ub.to_str(self.infcx()),
-               b.ub.to_str(self.infcx()),
-               ub.to_str(self.infcx()));
-        do merge_bnd(self, a.lb, b.lb, lub).chain |lb| {
-            debug!("lub of lbs %s and %s is %s",
-                   a.lb.to_str(self.infcx()),
-                   b.lb.to_str(self.infcx()),
-                   lb.to_str(self.infcx()));
-            Ok({lb: lb, ub: ub})
-        }
-    }
-}
-
-// Updates the bounds for the variable `v_id` to be the intersection
-// of `a` and `b`.  That is, the new bounds for `v_id` will be
-// a bounds c such that:
-//    c.ub <: a.ub
-//    c.ub <: b.ub
-//    a.lb <: c.lb
-//    b.lb <: c.lb
-// If this cannot be achieved, the result is failure.
-
-fn set_var_to_merged_bounds<C: combine>(
-    self: &C,
-    v_id: ty::TyVid,
-    a: bounds<ty::t>,
-    b: bounds<ty::t>,
-    rank: uint) -> ures {
-
-    let vb = &self.infcx().ty_var_bindings;
-
-    // Think of the two diamonds, we want to find the
-    // intersection.  There are basically four possibilities (you
-    // can swap A/B in these pictures):
-    //
-    //       A         A
-    //      / \       / \
-    //     / B \     / B \
-    //    / / \ \   / / \ \
-    //   * *   * * * /   * *
-    //    \ \ / /   \   / /
-    //     \ B /   / \ / /
-    //      \ /   *   \ /
-    //       A     \ / A
-    //              B
-
-    debug!("merge(%s,%s,%s)",
-           v_id.to_str(),
-           a.to_str(self.infcx()),
-           b.to_str(self.infcx()));
-
-    // First, relate the lower/upper bounds of A and B.
-    // Note that these relations *must* hold for us to
-    // to be able to merge A and B at all, and relating
-    // them explicitly gives the type inferencer more
-    // information and helps to produce tighter bounds
-    // when necessary.
-    do indent {
-        do bnds(self, a.lb, b.ub).then {
-            do bnds(self, b.lb, a.ub).then {
-                do merge_bnd(self, a.ub, b.ub,
-                             |x, y| self.glb().tys(x, y)).chain |ub| {
-                    do merge_bnd(self, a.lb, b.lb,
-                                 |x, y| self.lub().tys(x, y)).chain |lb| {
-                        let bounds = {lb: lb, ub: ub};
-                        debug!("merge(%s): bounds=%s",
-                               v_id.to_str(),
-                               bounds.to_str(self.infcx()));
-
-                        // the new bounds must themselves
-                        // be relatable:
-                        do bnds(self, bounds.lb, bounds.ub).then {
-                            self.infcx().set(vb, v_id, root(bounds, rank));
-                            uok()
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-/// Ensure that variable A is a subtype of variable B.  This is a
-/// subtle and tricky process, as described in detail at the top
-/// of infer.rs
-fn var_sub_var<C: combine>(self: &C,
-                           a_id: ty::TyVid,
-                           b_id: ty::TyVid) -> ures {
-    let vb = &self.infcx().ty_var_bindings;
-
-    // Need to make sub_id a subtype of sup_id.
-    let nde_a = self.infcx().get(vb, a_id);
-    let nde_b = self.infcx().get(vb, b_id);
-    let a_id = nde_a.root;
-    let b_id = nde_b.root;
-    let a_bounds = nde_a.possible_types;
-    let b_bounds = nde_b.possible_types;
-
-    debug!("vars(%s=%s <: %s=%s)",
-           a_id.to_str(), a_bounds.to_str(self.infcx()),
-           b_id.to_str(), b_bounds.to_str(self.infcx()));
-
-    if a_id == b_id { return uok(); }
-
-    // If both A's UB and B's LB have already been bound to types,
-    // see if we can make those types subtypes.
-    match (a_bounds.ub, b_bounds.lb) {
-      (Some(a_ub), Some(b_lb)) => {
-        let r = self.infcx().try(|| self.sub().tys(a_ub, b_lb));
-        match r {
-          Ok(_ty) => return result::Ok(()),
-          Err(_) => { /*fallthrough */ }
-        }
-      }
-      _ => { /*fallthrough*/ }
-    }
-
-    // Otherwise, we need to merge A and B so as to guarantee that
-    // A remains a subtype of B.  Actually, there are other options,
-    // but that's the route we choose to take.
-
-    // Rank optimization
-
-    // Make the node with greater rank the parent of the node with
-    // smaller rank.
-    if nde_a.rank > nde_b.rank {
-        debug!("vars(): a has smaller rank");
-        // a has greater rank, so a should become b's parent,
-        // i.e., b should redirect to a.
-        self.infcx().set(vb, b_id, redirect(a_id));
-        set_var_to_merged_bounds(
-            self, a_id, a_bounds, b_bounds, nde_a.rank)
-    } else if nde_a.rank < nde_b.rank {
-        debug!("vars(): b has smaller rank");
-        // b has greater rank, so a should redirect to b.
-        self.infcx().set(vb, a_id, redirect(b_id));
-        set_var_to_merged_bounds(
-            self, b_id, a_bounds, b_bounds, nde_b.rank)
-    } else {
-        debug!("vars(): a and b have equal rank");
-        assert nde_a.rank == nde_b.rank;
-        // If equal, just redirect one to the other and increment
-        // the other's rank.  We choose arbitrarily to redirect b
-        // to a and increment a's rank.
-        self.infcx().set(vb, b_id, redirect(a_id));
-        set_var_to_merged_bounds(
-            self, a_id, a_bounds, b_bounds, nde_a.rank + 1u
-        )
-    }
-}
-
-/// make variable a subtype of T
-fn var_sub_t<C: combine>(self: &C, a_id: ty::TyVid, b: ty::t) -> ures {
-
-    let vb = &self.infcx().ty_var_bindings;
-    let nde_a = self.infcx().get(vb, a_id);
-    let a_id = nde_a.root;
-    let a_bounds = nde_a.possible_types;
-
-    debug!("var_sub_t(%s=%s <: %s)",
-           a_id.to_str(),
-           a_bounds.to_str(self.infcx()),
-           b.to_str(self.infcx()));
-    let b_bounds = {lb: None, ub: Some(b)};
-    set_var_to_merged_bounds(self, a_id, a_bounds, b_bounds, nde_a.rank)
-}
-
-/// make T a subtype of variable
-fn t_sub_var<C: combine>(self: &C, a: ty::t, b_id: ty::TyVid) -> ures {
-
-    let vb = &self.infcx().ty_var_bindings;
-    let a_bounds = {lb: Some(a), ub: None};
-    let nde_b = self.infcx().get(vb, b_id);
-    let b_id = nde_b.root;
-    let b_bounds = nde_b.possible_types;
-
-    debug!("t_sub_var(%s <: %s=%s)",
-           a.to_str(self.infcx()),
-           b_id.to_str(),
-           b_bounds.to_str(self.infcx()));
-    set_var_to_merged_bounds(self, b_id, a_bounds, b_bounds, nde_b.rank)
-}
 
-fn bnds<C: combine>(
-    self: &C, a: bound<ty::t>, b: bound<ty::t>) -> ures {
-
-    debug!("bnds(%s <: %s)", a.to_str(self.infcx()), b.to_str(self.infcx()));
-    do indent {
-        match (a, b) {
-          (None, None) |
-          (Some(_), None) |
-          (None, Some(_)) => {
-            uok()
-          }
-          (Some(t_a), Some(t_b)) => {
-            self.sub().tys(t_a, t_b).to_ures()
-          }
-        }
-    }
-}
-
-// ______________________________________________________________________
-// Integral variables
-
-impl infer_ctxt {
-    fn optimize_ranks<V:Copy vid Eq,T:Copy ToStr>(vb: &vals_and_bindings<V,T>,
-                                                  nde_a: node<V,T>,
-                                                  nde_b: node<V,T>,
-                                                  a_id: V,
-                                                  b_id: V,
-                                                  intersection: T) {
-        if nde_a.rank > nde_b.rank {
-            debug!("int_vars(): a has smaller rank");
+    fn unify<V:Copy Vid ToStr, T:Copy InferStr, R>(
+        vb: &ValsAndBindings<V, T>,
+        node_a: &Node<V, T>,
+        node_b: &Node<V, T>,
+        op: &fn(new_root: V, new_rank: uint) -> R
+    ) -> R {
+        // Rank optimization: if you don't know what it is, check
+        // out <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>
+
+        debug!("unify(node_a(id=%?, rank=%?), \
+                node_b(id=%?, rank=%?))",
+               node_a.root, node_a.rank,
+               node_b.root, node_b.rank);
+
+        if node_a.rank > node_b.rank {
             // a has greater rank, so a should become b's parent,
             // i.e., b should redirect to a.
-            self.set(vb, a_id, root(intersection, nde_a.rank));
-            self.set(vb, b_id, redirect(a_id));
-        } else if nde_a.rank < nde_b.rank {
-            debug!("int_vars(): b has smaller rank");
+            self.set(vb, node_b.root, Redirect(node_a.root));
+            op(node_a.root, node_a.rank)
+        } else if node_a.rank < node_b.rank {
             // b has greater rank, so a should redirect to b.
-            self.set(vb, b_id, root(intersection, nde_b.rank));
-            self.set(vb, a_id, redirect(b_id));
+            self.set(vb, node_a.root, Redirect(node_b.root));
+            op(node_b.root, node_b.rank)
         } else {
-            debug!("int_vars(): a and b have equal rank");
-            assert nde_a.rank == nde_b.rank;
-            // If equal, just redirect one to the other and increment
-            // the other's rank.  We choose arbitrarily to redirect b
-            // to a and increment a's rank.
-            self.set(vb, a_id, root(intersection, nde_a.rank + 1u));
-            self.set(vb, b_id, redirect(a_id));
-        };
-    }
-
-    fn int_vars(a_id: ty::IntVid, b_id: ty::IntVid) -> ures {
-        let vb = &self.int_var_bindings;
-
-        let nde_a = self.get(vb, a_id);
-        let nde_b = self.get(vb, b_id);
-        let a_id = nde_a.root;
-        let b_id = nde_b.root;
-        let a_pt = nde_a.possible_types;
-        let b_pt = nde_b.possible_types;
-
-        // If we're already dealing with the same two variables,
-        // there's nothing to do.
-        if a_id == b_id { return uok(); }
-
-        // Otherwise, take the intersection of the two sets of
-        // possible types.
-        let intersection = integral::intersection(a_pt, b_pt);
-        if *intersection == INT_TY_SET_EMPTY {
-            return Err(ty::terr_no_integral_type);
+            // If equal, redirect one to the other and increment the
+            // other's rank.
+            assert node_a.rank == node_b.rank;
+            self.set(vb, node_b.root, Redirect(node_a.root));
+            op(node_a.root, node_a.rank + 1)
         }
-
-        // Rank optimization
-        self.optimize_ranks(vb, nde_a, nde_b, a_id, b_id, intersection);
-
-        uok()
     }
 
-    fn int_var_sub_t(a_id: ty::IntVid, b: ty::t) -> ures {
-        if ty::type_is_char(b) {
-            return Err(ty::terr_integer_as_char);
-        }
-
-        assert ty::type_is_integral(b);
-
-        let vb = &self.int_var_bindings;
-        let nde_a = self.get(vb, a_id);
-        let a_id = nde_a.root;
-        let a_pt = nde_a.possible_types;
-
-        let intersection =
-            integral::intersection(a_pt,
-                         convert_integral_ty_to_int_ty_set(self.tcx, b));
-        if *intersection == INT_TY_SET_EMPTY {
-            return Err(ty::terr_no_integral_type);
-        }
-        self.set(vb, a_id, root(intersection, nde_a.rank));
-        uok()
-    }
-
-    fn t_sub_int_var(a: ty::t, b_id: ty::IntVid) -> ures {
-        assert ty::type_is_integral(a);
-        let vb = &self.int_var_bindings;
-
-        let nde_b = self.get(vb, b_id);
-        let b_id = nde_b.root;
-        let b_pt = nde_b.possible_types;
-
-        let intersection =
-            integral::intersection(b_pt,
-                         convert_integral_ty_to_int_ty_set(self.tcx, a));
-        if *intersection == INT_TY_SET_EMPTY {
-            return Err(ty::terr_no_integral_type);
-        }
-        self.set(vb, b_id, root(intersection, nde_b.rank));
-        uok()
-    }
-
-
 }
 
 // ______________________________________________________________________
-// Floating point variables
-
-impl infer_ctxt {
-    fn float_vars(a_id: ty::FloatVid, b_id: ty::FloatVid) -> ures {
-        let vb = &self.float_var_bindings;
-
-        let nde_a = self.get(vb, a_id);
-        let nde_b = self.get(vb, b_id);
-        let a_id = nde_a.root;
-        let b_id = nde_b.root;
-        let a_pt = nde_a.possible_types;
-        let b_pt = nde_b.possible_types;
+// Code to handle simple variables like ints, floats---anything that
+// doesn't have a subtyping relationship we need to worry about.
+
+impl @InferCtxt {
+    fn simple_vars<V:Copy Eq Vid ToStr, T:Copy Eq InferStr>(
+        vb: &ValsAndBindings<V, Option<T>>,
+        err: ty::type_err,
+        a_id: V,
+        b_id: V) -> ures
+    {
+        /*!
+         *
+         * Unifies two simple variables.  Because simple variables do
+         * not have any subtyping relationships, if both variables
+         * have already been associated with a value, then those two
+         * values must be the same. */
+
+        let node_a = self.get(vb, a_id);
+        let node_b = self.get(vb, b_id);
+        let a_id = node_a.root;
+        let b_id = node_b.root;
 
-        // If we're already dealing with the same two variables,
-        // there's nothing to do.
         if a_id == b_id { return uok(); }
 
-        // Otherwise, take the intersection of the two sets of
-        // possible types.
-        let intersection = floating::intersection(a_pt, b_pt);
-        if *intersection == FLOAT_TY_SET_EMPTY {
-            return Err(ty::terr_no_floating_point_type);
-        }
-
-        // Rank optimization
-        self.optimize_ranks(vb, nde_a, nde_b, a_id, b_id, intersection);
+        let combined = match (&node_a.possible_types, &node_b.possible_types)
+        {
+            (&None, &None) => None,
+            (&Some(ref v), &None) | (&None, &Some(ref v)) => Some(*v),
+            (&Some(ref v1), &Some(ref v2)) => {
+                if *v1 != *v2 { return Err(err); }
+                Some(*v1)
+            }
+        };
 
-        uok()
+        self.unify(vb, &node_a, &node_b, |new_root, new_rank| {
+            self.set(vb, new_root, Root(combined, new_rank));
+        });
+        return uok();
     }
 
-    fn float_var_sub_t(a_id: ty::FloatVid, b: ty::t) -> ures {
-        assert ty::type_is_fp(b);
-
-        let vb = &self.float_var_bindings;
-        let nde_a = self.get(vb, a_id);
-        let a_id = nde_a.root;
-        let a_pt = nde_a.possible_types;
-
-        let intersection =
-            floating::intersection(
-                a_pt,
-                convert_floating_point_ty_to_float_ty_set(self.tcx, b));
-        if *intersection == FLOAT_TY_SET_EMPTY {
-            return Err(ty::terr_no_floating_point_type);
+    fn simple_var_t<V:Copy Eq Vid ToStr, T:Copy Eq InferStr>(
+        vb: &ValsAndBindings<V, Option<T>>,
+        err: ty::type_err,
+        a_id: V,
+        b: T) -> ures
+    {
+        /*!
+         *
+         * Sets the value of the variable `a_id` to `b`.  Because
+         * simple variables do not have any subtyping relationships,
+         * if `a_id` already has a value, it must be the same as
+         * `b`. */
+
+        let node_a = self.get(vb, a_id);
+        let a_id = node_a.root;
+
+        if node_a.possible_types.is_none() {
+            self.set(vb, a_id, Root(Some(b), node_a.rank));
+            return uok();
         }
-        self.set(vb, a_id, root(intersection, nde_a.rank));
-        uok()
-    }
-
-    fn t_sub_float_var(a: ty::t, b_id: ty::FloatVid) -> ures {
-        assert ty::type_is_fp(a);
-        let vb = &self.float_var_bindings;
 
-        let nde_b = self.get(vb, b_id);
-        let b_id = nde_b.root;
-        let b_pt = nde_b.possible_types;
-
-        let intersection =
-            floating::intersection(
-                b_pt,
-                convert_floating_point_ty_to_float_ty_set(self.tcx, a));
-        if *intersection == FLOAT_TY_SET_EMPTY {
-            return Err(ty::terr_no_floating_point_type);
+        if node_a.possible_types == Some(b) {
+            return uok();
         }
-        self.set(vb, b_id, root(intersection, nde_b.rank));
-        uok()
+
+        return Err(err);
     }
 }
 
diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs
index f922e83a164..509fe96508b 100644
--- a/src/librustc/middle/typeck/mod.rs
+++ b/src/librustc/middle/typeck/mod.rs
@@ -271,7 +271,7 @@ fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
 
 fn require_same_types(
     tcx: ty::ctxt,
-    maybe_infcx: Option<infer::infer_ctxt>,
+    maybe_infcx: Option<@infer::InferCtxt>,
     t1_is_expected: bool,
     span: span,
     t1: ty::t,
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 1a556c32bf3..528b997c8e6 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -69,8 +69,9 @@ fn loop_query(b: ast::blk, p: fn@(ast::expr_) -> bool) -> bool {
           _ => visit::visit_expr(e, flag, v)
         }
     };
-    let v = visit::mk_vt(@{visit_expr: visit_expr
-                           ,.. *visit::default_visitor()});
+    let v = visit::mk_vt(@visit::Visitor {
+        visit_expr: visit_expr,
+        .. *visit::default_visitor()});
     visit::visit_block(b, rs, v);
     return *rs;
 }
@@ -84,8 +85,9 @@ fn block_query(b: ast::blk, p: fn@(@ast::expr) -> bool) -> bool {
         *flag |= p(e);
         visit::visit_expr(e, flag, v)
     };
-    let v = visit::mk_vt(@{visit_expr: visit_expr
-                           ,.. *visit::default_visitor()});
+    let v = visit::mk_vt(@visit::Visitor{
+        visit_expr: visit_expr,
+        .. *visit::default_visitor()});
     visit::visit_block(b, rs, v);
     return *rs;
 }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index ebb75de8626..3cd38d67a29 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -25,14 +25,12 @@ use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_fn, ty_trait, ty_int};
 use middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param};
 use middle::ty::{ty_ptr, ty_rec, ty_rptr, ty_self, ty_tup};
 use middle::ty::{ty_type, ty_uniq, ty_uint, ty_infer};
-use middle::ty::{ty_unboxed_vec, vid};
+use middle::ty::{ty_unboxed_vec};
 use metadata::encoder;
 use syntax::codemap;
 use syntax::codemap::span;
 use syntax::print::pprust;
-use syntax::print::pprust::{path_to_str, proto_to_str,
-                            mode_to_str, purity_to_str,
-                            onceness_to_str};
+use syntax::print::pprust::{path_to_str, proto_to_str, mode_to_str};
 use syntax::{ast, ast_util};
 use syntax::ast_map;
 
@@ -248,9 +246,11 @@ fn vstore_ty_to_str(cx: ctxt, ty: ~str, vs: ty::vstore) -> ~str {
     }
 }
 
-fn proto_ty_to_str(_cx: ctxt, proto: ast::Proto) -> &static/str {
+fn proto_ty_to_str(_cx: ctxt, proto: ast::Proto,
+                   followed_by_word: bool) -> &static/str {
     match proto {
-        ast::ProtoBare => "",
+        ast::ProtoBare if followed_by_word => "extern ",
+        ast::ProtoBare => "extern",
         ast::ProtoBox => "@",
         ast::ProtoBorrowed => "&",
         ast::ProtoUniq => "~",
@@ -265,13 +265,19 @@ fn expr_repr(cx: ctxt, expr: @ast::expr) -> ~str {
 
 fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str {
     let tstrs = ts.map(|t| ty_to_str(cx, *t));
-    fmt!("[%s]", str::connect(tstrs, ", "))
+    fmt!("(%s)", str::connect(tstrs, ", "))
 }
 
 fn bound_to_str(cx: ctxt, b: param_bound) -> ~str {
     ty::param_bound_to_str(cx, &b)
 }
 
+fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str {
+    fmt!("fn%s -> %s",
+         tys_to_str(cx, typ.inputs.map(|a| a.ty)),
+         ty_to_str(cx, typ.output))
+}
+
 fn ty_to_str(cx: ctxt, typ: t) -> ~str {
     fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
        ~str {
@@ -301,15 +307,15 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
 
         s = match purity {
             ast::impure_fn => ~"",
-            _ => purity_to_str(purity) + ~" "
+            _ => purity.to_str() + ~" "
         };
 
         s += match onceness {
             ast::Many => ~"",
-            ast::Once => onceness_to_str(onceness) + ~" "
+            ast::Once => onceness.to_str() + ~" "
         };
 
-        s += proto_ty_to_str(cx, proto);
+        s += proto_ty_to_str(cx, proto, true);
 
         match (proto, region) {
             (ast::ProtoBox, ty::re_static) |
diff --git a/src/librustdoc/attr_pass.rs b/src/librustdoc/attr_pass.rs
index 530f9f22666..165b5e257b2 100644
--- a/src/librustdoc/attr_pass.rs
+++ b/src/librustdoc/attr_pass.rs
@@ -35,7 +35,7 @@ use std::map::HashMap;
 use std::par;
 
 pub fn mk_pass() -> Pass {
-    {
+    Pass {
         name: ~"attr",
         f: run
     }
diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs
index 97caa71d692..4074d9aa691 100644
--- a/src/librustdoc/desc_to_brief_pass.rs
+++ b/src/librustdoc/desc_to_brief_pass.rs
@@ -29,7 +29,7 @@ use core::vec;
 use std::par;
 
 pub fn mk_pass() -> Pass {
-    {
+    Pass {
         name: ~"desc_to_brief",
         f: run
     }
diff --git a/src/librustdoc/markdown_index_pass.rs b/src/librustdoc/markdown_index_pass.rs
index 881352c9c77..1f4e1be62fc 100644
--- a/src/librustdoc/markdown_index_pass.rs
+++ b/src/librustdoc/markdown_index_pass.rs
@@ -26,7 +26,7 @@ use core::str;
 use std::par;
 
 pub fn mk_pass(+config: config::Config) -> Pass {
-    {
+    Pass {
         name: ~"markdown_index",
         f: fn~(srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc {
             run(srv, doc, config)
diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs
index ad100b9b4e8..1ec30bc74ab 100644
--- a/src/librustdoc/markdown_pass.rs
+++ b/src/librustdoc/markdown_pass.rs
@@ -47,7 +47,7 @@ pub fn mk_pass(+writer_factory: WriterFactory) -> Pass {
         run(srv, doc, copy writer_factory)
     };
 
-    {
+    Pass {
         name: ~"markdown",
         f: move f
     }
diff --git a/src/librustdoc/page_pass.rs b/src/librustdoc/page_pass.rs
index c8e2865e986..2629d45635e 100644
--- a/src/librustdoc/page_pass.rs
+++ b/src/librustdoc/page_pass.rs
@@ -34,7 +34,7 @@ use core::vec;
 use syntax::ast;
 
 pub fn mk_pass(output_style: config::OutputStyle) -> Pass {
-    {
+    Pass {
         name: ~"page",
         f: fn~(srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc {
             run(srv, doc, output_style)
diff --git a/src/librustdoc/pass.rs b/src/librustdoc/pass.rs
index e6b85ca9d64..1e5d5542963 100644
--- a/src/librustdoc/pass.rs
+++ b/src/librustdoc/pass.rs
@@ -18,10 +18,10 @@ use time;
 use core::vec;
 
 /// A single operation on the document model
-pub type Pass = {
+pub struct Pass {
     name: ~str,
     f: fn~(srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc
-};
+}
 
 pub fn run_passes(
     srv: astsrv::Srv,
@@ -82,11 +82,11 @@ fn test_run_passes() {
     let source = ~"";
     do astsrv::from_str(source) |srv| {
         let passes = ~[
-            {
+            Pass {
                 name: ~"",
                 f: pass1
             },
-            {
+            Pass {
                 name: ~"",
                 f: pass2
             }
diff --git a/src/librustdoc/path_pass.rs b/src/librustdoc/path_pass.rs
index 01ea26e1ad0..48ed1878771 100644
--- a/src/librustdoc/path_pass.rs
+++ b/src/librustdoc/path_pass.rs
@@ -23,7 +23,7 @@ use pass::Pass;
 use syntax::ast;
 
 pub fn mk_pass() -> Pass {
-    {
+    Pass {
         name: ~"path",
         f: run
     }
diff --git a/src/librustdoc/prune_hidden_pass.rs b/src/librustdoc/prune_hidden_pass.rs
index 74c4b881eb3..3a924e3bddf 100644
--- a/src/librustdoc/prune_hidden_pass.rs
+++ b/src/librustdoc/prune_hidden_pass.rs
@@ -22,7 +22,7 @@ use core::vec;
 use std::map::HashMap;
 
 pub fn mk_pass() -> Pass {
-    {
+    Pass {
         name: ~"prune_hidden",
         f: run
     }
diff --git a/src/librustdoc/prune_private_pass.rs b/src/librustdoc/prune_private_pass.rs
index f3db152696e..615bd07ca85 100644
--- a/src/librustdoc/prune_private_pass.rs
+++ b/src/librustdoc/prune_private_pass.rs
@@ -28,7 +28,7 @@ export mk_pass;
 export run;
 
 fn mk_pass() -> Pass {
-    {
+    Pass {
         name: ~"prune_private",
         f: run
     }
diff --git a/src/librustdoc/sectionalize_pass.rs b/src/librustdoc/sectionalize_pass.rs
index a9cb8aa1e5d..eeadd82371f 100644
--- a/src/librustdoc/sectionalize_pass.rs
+++ b/src/librustdoc/sectionalize_pass.rs
@@ -26,7 +26,7 @@ use core::vec;
 use std::par;
 
 pub fn mk_pass() -> Pass {
-    {
+    Pass {
         name: ~"sectionalize",
         f: run
     }
diff --git a/src/librustdoc/sort_pass.rs b/src/librustdoc/sort_pass.rs
index c6d2ab0e9ad..b3ecb8173fe 100644
--- a/src/librustdoc/sort_pass.rs
+++ b/src/librustdoc/sort_pass.rs
@@ -28,7 +28,7 @@ pub type ItemLtEqOp = pure fn~(v1: &doc::ItemTag, v2:  &doc::ItemTag) -> bool;
 type ItemLtEq = NominalOp<ItemLtEqOp>;
 
 pub fn mk_pass(name: ~str, +lteq: ItemLtEqOp) -> Pass {
-    {
+    Pass {
         name: name,
         f: fn~(move lteq, srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc {
             run(srv, doc, NominalOp { op: copy lteq })
diff --git a/src/librustdoc/text_pass.rs b/src/librustdoc/text_pass.rs
index 975767727c5..5627bfead9f 100644
--- a/src/librustdoc/text_pass.rs
+++ b/src/librustdoc/text_pass.rs
@@ -23,7 +23,7 @@ use util::NominalOp;
 use std::par;
 
 pub fn mk_pass(name: ~str, +op: fn~(~str) -> ~str) -> Pass {
-    {
+    Pass {
         name: name,
         f: fn~(move op, srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc {
             run(srv, doc, copy op)
diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs
index 97d57569c73..ae1b7577ad8 100644
--- a/src/librustdoc/tystr_pass.rs
+++ b/src/librustdoc/tystr_pass.rs
@@ -29,7 +29,7 @@ use syntax::print::pprust;
 use syntax::ast_map;
 
 pub fn mk_pass() -> Pass {
-    {
+    Pass {
         name: ~"tystr",
         f: run
     }
diff --git a/src/libstd/test.rs b/src/libstd/test.rs
index 8b4c53604bc..12064e56bed 100644
--- a/src/libstd/test.rs
+++ b/src/libstd/test.rs
@@ -56,12 +56,12 @@ pub type TestFn = fn~();
 
 // The definition of a single test. A test runner will run a list of
 // these.
-pub type TestDesc = {
+pub struct TestDesc {
     name: TestName,
     testfn: TestFn,
     ignore: bool,
     should_fail: bool
-};
+}
 
 // The default console test runner. It accepts the command line
 // arguments and a vector of test_descs (generated at compile time).
@@ -242,14 +242,14 @@ fn print_failures(st: ConsoleTestState) {
 #[test]
 fn should_sort_failures_before_printing_them() {
     let s = do io::with_str_writer |wr| {
-        let test_a = {
+        let test_a = TestDesc {
             name: ~"a",
             testfn: fn~() { },
             ignore: false,
             should_fail: false
         };
 
-        let test_b = {
+        let test_b = TestDesc {
             name: ~"b",
             testfn: fn~() { },
             ignore: false,
@@ -372,10 +372,11 @@ pub fn filter_tests(opts: &TestOpts,
     } else {
         fn filter(test: &TestDesc) -> Option<TestDesc> {
             if test.ignore {
-                return option::Some({name: test.name,
-                                  testfn: copy test.testfn,
-                                  ignore: false,
-                                  should_fail: test.should_fail});
+                return option::Some(TestDesc {
+                    name: test.name,
+                    testfn: copy test.testfn,
+                    ignore: false,
+                    should_fail: test.should_fail});
             } else { return option::None; }
         };
 
@@ -427,7 +428,8 @@ fn calc_result(test: &TestDesc, task_succeeded: bool) -> TestResult {
 mod tests {
     #[legacy_exports];
 
-    use test::{TrFailed, TrIgnored, TrOk, filter_tests, parse_opts, run_test};
+    use test::{TrFailed, TrIgnored, TrOk, filter_tests, parse_opts, TestDesc};
+    use test::{run_test};
 
     use core::either;
     use core::oldcomm;
@@ -437,7 +439,7 @@ mod tests {
     #[test]
     fn do_not_run_ignored_tests() {
         fn f() { fail; }
-        let desc = {
+        let desc = TestDesc {
             name: ~"whatever",
             testfn: f,
             ignore: true,
@@ -453,7 +455,7 @@ mod tests {
     #[test]
     fn ignored_tests_result_in_ignored() {
         fn f() { }
-        let desc = {
+        let desc = TestDesc {
             name: ~"whatever",
             testfn: f,
             ignore: true,
@@ -470,7 +472,7 @@ mod tests {
     #[ignore(cfg(windows))]
     fn test_should_fail() {
         fn f() { fail; }
-        let desc = {
+        let desc = TestDesc {
             name: ~"whatever",
             testfn: f,
             ignore: false,
@@ -486,7 +488,7 @@ mod tests {
     #[test]
     fn test_should_fail_but_succeeds() {
         fn f() { }
-        let desc = {
+        let desc = TestDesc {
             name: ~"whatever",
             testfn: f,
             ignore: false,
@@ -527,10 +529,10 @@ mod tests {
         let opts = {filter: option::None, run_ignored: true,
             logfile: option::None};
         let tests =
-            ~[{name: ~"1", testfn: fn~() { },
-               ignore: true, should_fail: false},
-             {name: ~"2", testfn: fn~() { },
-              ignore: false, should_fail: false}];
+            ~[TestDesc {name: ~"1", testfn: fn~() { },
+                        ignore: true, should_fail: false},
+              TestDesc {name: ~"2", testfn: fn~() { },
+                        ignore: false, should_fail: false}];
         let filtered = filter_tests(&opts, tests);
 
         assert (vec::len(filtered) == 1u);
@@ -555,8 +557,9 @@ mod tests {
             let testfn = fn~() { };
             let mut tests = ~[];
             for vec::each(names) |name| {
-                let test = {name: *name, testfn: copy testfn, ignore: false,
-                            should_fail: false};
+                let test = TestDesc {
+                    name: *name, testfn: copy testfn, ignore: false,
+                    should_fail: false};
                 tests.push(move test);
             }
             move tests
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index b71f62c6db2..072a7e94fe9 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -19,6 +19,7 @@ use core::option::{None, Option, Some};
 use core::ptr;
 use core::task;
 use core::to_bytes;
+use core::to_str::ToStr;
 use std::serialize::{Encodable, Decodable, Encoder, Decoder};
 
 #[auto_encode]
@@ -415,6 +416,7 @@ impl mutability : cmp::Eq {
 
 #[auto_encode]
 #[auto_decode]
+#[deriving_eq]
 pub enum Proto {
     ProtoBare,     // bare functions (deprecated)
     ProtoUniq,     // ~fn
@@ -422,13 +424,6 @@ pub enum Proto {
     ProtoBorrowed, // &fn
 }
 
-impl Proto : cmp::Eq {
-    pure fn eq(&self, other: &Proto) -> bool {
-        ((*self) as uint) == ((*other) as uint)
-    }
-    pure fn ne(&self, other: &Proto) -> bool { !(*self).eq(other) }
-}
-
 impl Proto : to_bytes::IterBytes {
     pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
         (*self as uint).iter_bytes(lsb0, f);
@@ -1068,20 +1063,24 @@ enum region_ {
 
 #[auto_encode]
 #[auto_decode]
+#[deriving_eq]
 enum Onceness {
     Once,
     Many
 }
 
-impl Onceness : cmp::Eq {
-    pure fn eq(&self, other: &Onceness) -> bool {
-        match ((*self), *other) {
-            (Once, Once) | (Many, Many) => true,
-            _ => false
+impl Onceness : ToStr {
+    pure fn to_str() -> ~str {
+        match self {
+            ast::Once => ~"once",
+            ast::Many => ~"many"
         }
     }
-    pure fn ne(&self, other: &Onceness) -> bool {
-        !(*self).eq(other)
+}
+
+impl Onceness : to_bytes::IterBytes {
+    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
+        (*self as uint).iter_bytes(lsb0, f);
     }
 }
 
@@ -1156,6 +1155,17 @@ pub enum purity {
     extern_fn, // declared with "extern fn"
 }
 
+impl purity : ToStr {
+    pure fn to_str() -> ~str {
+        match self {
+            impure_fn => ~"impure",
+            unsafe_fn => ~"unsafe",
+            pure_fn => ~"pure",
+            extern_fn => ~"extern"
+        }
+    }
+}
+
 impl purity : to_bytes::IterBytes {
     pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
         (*self as u8).iter_bytes(lsb0, f)
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
index 81c7bb2abc9..9ddf1b24040 100644
--- a/src/libsyntax/ast_map.rs
+++ b/src/libsyntax/ast_map.rs
@@ -110,7 +110,7 @@ fn extend(cx: ctx, +elt: ident) -> @path {
 }
 
 fn mk_ast_map_visitor() -> vt {
-    return visit::mk_vt(@{
+    return visit::mk_vt(@visit::Visitor {
         visit_item: map_item,
         visit_expr: map_expr,
         visit_stmt: map_stmt,
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 55ac2ae0964..1a34fe29a71 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -440,10 +440,8 @@ fn empty(range: id_range) -> bool {
 }
 
 fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
-    visit::mk_simple_visitor(@{
-        visit_mod: fn@(_m: _mod, _sp: span, id: node_id) {
-            vfn(id)
-        },
+    visit::mk_simple_visitor(@visit::SimpleVisitor {
+        visit_mod: |_m, _sp, id| vfn(id),
 
         visit_view_item: fn@(vi: @view_item) {
             match vi.node {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 82dae3e26b3..e3fb7a289c1 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -322,13 +322,13 @@ fn expand_crate(parse_sess: parse::parse_sess,
     let exts = syntax_expander_table();
     let afp = default_ast_fold();
     let cx: ext_ctxt = mk_ctxt(parse_sess, cfg);
-    let f_pre =
-        @{fold_expr: |a,b,c| expand_expr(exts, cx, a, b, c, afp.fold_expr),
-          fold_mod: |a,b| expand_mod_items(exts, cx, a, b, afp.fold_mod),
-          fold_item: |a,b| expand_item(exts, cx, a, b, afp.fold_item),
-          fold_stmt: |a,b,c| expand_stmt(exts, cx, a, b, c, afp.fold_stmt),
-          new_span: |a| new_span(cx, a),
-          .. *afp};
+    let f_pre = @AstFoldFns {
+        fold_expr: |a,b,c| expand_expr(exts, cx, a, b, c, afp.fold_expr),
+        fold_mod: |a,b| expand_mod_items(exts, cx, a, b, afp.fold_mod),
+        fold_item: |a,b| expand_item(exts, cx, a, b, afp.fold_item),
+        fold_stmt: |a,b,c| expand_stmt(exts, cx, a, b, c, afp.fold_stmt),
+        new_span: |a| new_span(cx, a),
+        .. *afp};
     let f = make_fold(f_pre);
     let cm = parse_expr_from_source_str(~"<core-macros>",
                                         @core_macros(),
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 2c4efa82499..272ad3456e5 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -17,7 +17,7 @@ use codemap::span;
 use core::option;
 use core::vec;
 
-export ast_fold_precursor;
+export ast_fold_fns;
 export ast_fold;
 export default_ast_fold;
 export make_fold;
@@ -34,6 +34,7 @@ export fold_ty_param;
 export fold_ty_params;
 export fold_fn_decl;
 export extensions;
+export AstFoldFns;
 
 trait ast_fold {
     fn fold_crate(crate) -> crate;
@@ -63,7 +64,7 @@ trait ast_fold {
 
 // We may eventually want to be able to fold over type parameters, too
 
-type ast_fold_precursor = @{
+struct AstFoldFns {
     //unlike the others, item_ is non-trivial
     fold_crate: fn@(crate_, span, ast_fold) -> (crate_, span),
     fold_view_item: fn@(view_item_, ast_fold) -> view_item_,
@@ -87,7 +88,10 @@ type ast_fold_precursor = @{
     fold_local: fn@(local_, span, ast_fold) -> (local_, span),
     map_exprs: fn@(fn@(&&v: @expr) -> @expr, ~[@expr]) -> ~[@expr],
     new_id: fn@(node_id) -> node_id,
-    new_span: fn@(span) -> span};
+    new_span: fn@(span) -> span
+}
+
+type ast_fold_fns = @AstFoldFns;
 
 /* some little folds that probably aren't useful to have in ast_fold itself*/
 
@@ -631,8 +635,8 @@ fn noop_id(i: node_id) -> node_id { return i; }
 
 fn noop_span(sp: span) -> span { return sp; }
 
-fn default_ast_fold() -> ast_fold_precursor {
-    return @{fold_crate: wrap(noop_fold_crate),
+fn default_ast_fold() -> ast_fold_fns {
+    return @AstFoldFns {fold_crate: wrap(noop_fold_crate),
           fold_view_item: noop_fold_view_item,
           fold_foreign_item: noop_fold_foreign_item,
           fold_item: noop_fold_item,
@@ -657,7 +661,7 @@ fn default_ast_fold() -> ast_fold_precursor {
           new_span: noop_span};
 }
 
-impl ast_fold_precursor: ast_fold {
+impl ast_fold_fns: ast_fold {
     /* naturally, a macro to write these would be nice */
     fn fold_crate(c: crate) -> crate {
         let (n, s) = (self.fold_crate)(c.node, c.span, self as ast_fold);
@@ -763,7 +767,7 @@ impl ast_fold {
     }
 }
 
-fn make_fold(afp: ast_fold_precursor) -> ast_fold {
+fn make_fold(afp: ast_fold_fns) -> ast_fold {
     afp as ast_fold
 }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index dda83aa2d0e..272c35152bb 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -44,11 +44,14 @@ enum ann_node {
     node_expr(ps, @ast::expr),
     node_pat(ps, @ast::pat),
 }
-type pp_ann = {pre: fn@(ann_node), post: fn@(ann_node)};
+struct pp_ann {
+    pre: fn@(ann_node),
+    post: fn@(ann_node)
+}
 
 fn no_ann() -> pp_ann {
     fn ignore(_node: ann_node) { }
-    return {pre: ignore, post: ignore};
+    return pp_ann {pre: ignore, post: ignore};
 }
 
 type ps =
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 3f7ba2dc37b..0da6396253e 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -59,51 +59,56 @@ fn tps_of_fn(fk: fn_kind) -> ~[ty_param] {
     }
 }
 
-type visitor<E> =
-    @{visit_mod: fn@(_mod, span, node_id, E, vt<E>),
-      visit_view_item: fn@(@view_item, E, vt<E>),
-      visit_foreign_item: fn@(@foreign_item, E, vt<E>),
-      visit_item: fn@(@item, E, vt<E>),
-      visit_local: fn@(@local, E, vt<E>),
-      visit_block: fn@(ast::blk, E, vt<E>),
-      visit_stmt: fn@(@stmt, E, vt<E>),
-      visit_arm: fn@(arm, E, vt<E>),
-      visit_pat: fn@(@pat, E, vt<E>),
-      visit_decl: fn@(@decl, E, vt<E>),
-      visit_expr: fn@(@expr, E, vt<E>),
-      visit_expr_post: fn@(@expr, E, vt<E>),
-      visit_ty: fn@(@Ty, E, vt<E>),
-      visit_ty_params: fn@(~[ty_param], E, vt<E>),
-      visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id, E, vt<E>),
-      visit_ty_method: fn@(ty_method, E, vt<E>),
-      visit_trait_method: fn@(trait_method, E, vt<E>),
-      visit_struct_def: fn@(@struct_def, ident, ~[ty_param], node_id, E,
-                            vt<E>),
-      visit_struct_field: fn@(@struct_field, E, vt<E>),
-      visit_struct_method: fn@(@method, E, vt<E>)};
+struct Visitor<E> {
+    visit_mod: fn@(_mod, span, node_id, E, vt<E>),
+    visit_view_item: fn@(@view_item, E, vt<E>),
+    visit_foreign_item: fn@(@foreign_item, E, vt<E>),
+    visit_item: fn@(@item, E, vt<E>),
+    visit_local: fn@(@local, E, vt<E>),
+    visit_block: fn@(ast::blk, E, vt<E>),
+    visit_stmt: fn@(@stmt, E, vt<E>),
+    visit_arm: fn@(arm, E, vt<E>),
+    visit_pat: fn@(@pat, E, vt<E>),
+    visit_decl: fn@(@decl, E, vt<E>),
+    visit_expr: fn@(@expr, E, vt<E>),
+    visit_expr_post: fn@(@expr, E, vt<E>),
+    visit_ty: fn@(@Ty, E, vt<E>),
+    visit_ty_params: fn@(~[ty_param], E, vt<E>),
+    visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id, E, vt<E>),
+    visit_ty_method: fn@(ty_method, E, vt<E>),
+    visit_trait_method: fn@(trait_method, E, vt<E>),
+    visit_struct_def: fn@(@struct_def, ident, ~[ty_param], node_id, E,
+                          vt<E>),
+    visit_struct_field: fn@(@struct_field, E, vt<E>),
+    visit_struct_method: fn@(@method, E, vt<E>)
+}
+
+type visitor<E> = @Visitor<E>;
 
 fn default_visitor<E>() -> visitor<E> {
-    return @{visit_mod: |a,b,c,d,e|visit_mod::<E>(a, b, c, d, e),
-          visit_view_item: |a,b,c|visit_view_item::<E>(a, b, c),
-          visit_foreign_item: |a,b,c|visit_foreign_item::<E>(a, b, c),
-          visit_item: |a,b,c|visit_item::<E>(a, b, c),
-          visit_local: |a,b,c|visit_local::<E>(a, b, c),
-          visit_block: |a,b,c|visit_block::<E>(a, b, c),
-          visit_stmt: |a,b,c|visit_stmt::<E>(a, b, c),
-          visit_arm: |a,b,c|visit_arm::<E>(a, b, c),
-          visit_pat: |a,b,c|visit_pat::<E>(a, b, c),
-          visit_decl: |a,b,c|visit_decl::<E>(a, b, c),
-          visit_expr: |a,b,c|visit_expr::<E>(a, b, c),
-          visit_expr_post: |_a,_b,_c| (),
-          visit_ty: |a,b,c|skip_ty::<E>(a, b, c),
-          visit_ty_params: |a,b,c|visit_ty_params::<E>(a, b, c),
-          visit_fn: |a,b,c,d,e,f,g|visit_fn::<E>(a, b, c, d, e, f, g),
-          visit_ty_method: |a,b,c|visit_ty_method::<E>(a, b, c),
-          visit_trait_method: |a,b,c|visit_trait_method::<E>(a, b, c),
-          visit_struct_def: |a,b,c,d,e,f|visit_struct_def::<E>(a, b, c,
-                                                               d, e, f),
-          visit_struct_field: |a,b,c|visit_struct_field::<E>(a, b, c),
-          visit_struct_method: |a,b,c|visit_struct_method::<E>(a, b, c)};
+    return @Visitor {
+        visit_mod: |a,b,c,d,e|visit_mod::<E>(a, b, c, d, e),
+        visit_view_item: |a,b,c|visit_view_item::<E>(a, b, c),
+        visit_foreign_item: |a,b,c|visit_foreign_item::<E>(a, b, c),
+        visit_item: |a,b,c|visit_item::<E>(a, b, c),
+        visit_local: |a,b,c|visit_local::<E>(a, b, c),
+        visit_block: |a,b,c|visit_block::<E>(a, b, c),
+        visit_stmt: |a,b,c|visit_stmt::<E>(a, b, c),
+        visit_arm: |a,b,c|visit_arm::<E>(a, b, c),
+        visit_pat: |a,b,c|visit_pat::<E>(a, b, c),
+        visit_decl: |a,b,c|visit_decl::<E>(a, b, c),
+        visit_expr: |a,b,c|visit_expr::<E>(a, b, c),
+        visit_expr_post: |_a,_b,_c| (),
+        visit_ty: |a,b,c|skip_ty::<E>(a, b, c),
+        visit_ty_params: |a,b,c|visit_ty_params::<E>(a, b, c),
+        visit_fn: |a,b,c,d,e,f,g|visit_fn::<E>(a, b, c, d, e, f, g),
+        visit_ty_method: |a,b,c|visit_ty_method::<E>(a, b, c),
+        visit_trait_method: |a,b,c|visit_trait_method::<E>(a, b, c),
+        visit_struct_def: |a,b,c,d,e,f|visit_struct_def::<E>(a, b, c,
+                                                             d, e, f),
+        visit_struct_field: |a,b,c|visit_struct_field::<E>(a, b, c),
+        visit_struct_method: |a,b,c|visit_struct_method::<E>(a, b, c)
+    };
 }
 
 fn visit_crate<E>(c: crate, e: E, v: vt<E>) {
@@ -499,43 +504,46 @@ fn visit_arm<E>(a: arm, e: E, v: vt<E>) {
 // Simpler, non-context passing interface. Always walks the whole tree, simply
 // calls the given functions on the nodes.
 
-type simple_visitor =
-    @{visit_mod: fn@(_mod, span, node_id),
-      visit_view_item: fn@(@view_item),
-      visit_foreign_item: fn@(@foreign_item),
-      visit_item: fn@(@item),
-      visit_local: fn@(@local),
-      visit_block: fn@(ast::blk),
-      visit_stmt: fn@(@stmt),
-      visit_arm: fn@(arm),
-      visit_pat: fn@(@pat),
-      visit_decl: fn@(@decl),
-      visit_expr: fn@(@expr),
-      visit_expr_post: fn@(@expr),
-      visit_ty: fn@(@Ty),
-      visit_ty_params: fn@(~[ty_param]),
-      visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id),
-      visit_ty_method: fn@(ty_method),
-      visit_trait_method: fn@(trait_method),
-      visit_struct_def: fn@(@struct_def, ident, ~[ty_param], node_id),
-      visit_struct_field: fn@(@struct_field),
-      visit_struct_method: fn@(@method)};
+struct SimpleVisitor {
+    visit_mod: fn@(_mod, span, node_id),
+    visit_view_item: fn@(@view_item),
+    visit_foreign_item: fn@(@foreign_item),
+    visit_item: fn@(@item),
+    visit_local: fn@(@local),
+    visit_block: fn@(ast::blk),
+    visit_stmt: fn@(@stmt),
+    visit_arm: fn@(arm),
+    visit_pat: fn@(@pat),
+    visit_decl: fn@(@decl),
+    visit_expr: fn@(@expr),
+    visit_expr_post: fn@(@expr),
+    visit_ty: fn@(@Ty),
+    visit_ty_params: fn@(~[ty_param]),
+    visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id),
+    visit_ty_method: fn@(ty_method),
+    visit_trait_method: fn@(trait_method),
+    visit_struct_def: fn@(@struct_def, ident, ~[ty_param], node_id),
+    visit_struct_field: fn@(@struct_field),
+    visit_struct_method: fn@(@method)
+}
+
+type simple_visitor = @SimpleVisitor;
 
 fn simple_ignore_ty(_t: @Ty) {}
 
-fn default_simple_visitor() -> simple_visitor {
-    return @{visit_mod: fn@(_m: _mod, _sp: span, _id: node_id) { },
-          visit_view_item: fn@(_vi: @view_item) { },
-          visit_foreign_item: fn@(_ni: @foreign_item) { },
-          visit_item: fn@(_i: @item) { },
-          visit_local: fn@(_l: @local) { },
-          visit_block: fn@(_b: ast::blk) { },
-          visit_stmt: fn@(_s: @stmt) { },
-          visit_arm: fn@(_a: arm) { },
-          visit_pat: fn@(_p: @pat) { },
-          visit_decl: fn@(_d: @decl) { },
-          visit_expr: fn@(_e: @expr) { },
-          visit_expr_post: fn@(_e: @expr) { },
+fn default_simple_visitor() -> @SimpleVisitor {
+    return @SimpleVisitor {visit_mod: |_m: _mod, _sp: span, _id: node_id| { },
+          visit_view_item: |_vi: @view_item| { },
+          visit_foreign_item: |_ni: @foreign_item| { },
+          visit_item: |_i: @item| { },
+          visit_local: |_l: @local| { },
+          visit_block: |_b: ast::blk| { },
+          visit_stmt: |_s: @stmt| { },
+          visit_arm: |_a: arm| { },
+          visit_pat: |_p: @pat| { },
+          visit_decl: |_d: @decl| { },
+          visit_expr: |_e: @expr| { },
+          visit_expr_post: |_e: @expr| { },
           visit_ty: simple_ignore_ty,
           visit_ty_params: fn@(_ps: ~[ty_param]) {},
           visit_fn: fn@(_fk: fn_kind, _d: fn_decl, _b: blk, _sp: span,
@@ -640,37 +648,37 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
         f(m);
         visit_struct_method(m, e, v);
     }
-    return mk_vt(@{visit_mod: |a,b,c,d,e|v_mod(v.visit_mod, a, b, c, d, e),
-                visit_view_item: |a,b,c|
-                    v_view_item(v.visit_view_item, a, b, c),
-                visit_foreign_item:
-                    |a,b,c|v_foreign_item(v.visit_foreign_item, a, b, c),
-                visit_item: |a,b,c|v_item(v.visit_item, a, b, c),
-                visit_local: |a,b,c|v_local(v.visit_local, a, b, c),
-                visit_block: |a,b,c|v_block(v.visit_block, a, b, c),
-                visit_stmt: |a,b,c|v_stmt(v.visit_stmt, a, b, c),
-                visit_arm: |a,b,c|v_arm(v.visit_arm, a, b, c),
-                visit_pat: |a,b,c|v_pat(v.visit_pat, a, b, c),
-                visit_decl: |a,b,c|v_decl(v.visit_decl, a, b, c),
-                visit_expr: |a,b,c|v_expr(v.visit_expr, a, b, c),
-                visit_expr_post: |a,b,c| v_expr_post(v.visit_expr_post,
-                                                     a, b, c),
-                visit_ty: visit_ty,
-                visit_ty_params: |a,b,c|
-                    v_ty_params(v.visit_ty_params, a, b, c),
-                visit_fn: |a,b,c,d,e,f,g|
-                    v_fn(v.visit_fn, a, b, c, d, e, f, g),
-                visit_ty_method: |a,b,c|
-                    v_ty_method(v.visit_ty_method, a, b, c),
-                visit_trait_method: |a,b,c|
-                    v_trait_method(v.visit_trait_method, a, b, c),
-                visit_struct_def: |a,b,c,d,e,f|
-                    v_struct_def(v.visit_struct_def, a, b, c, d, e, f),
-                visit_struct_field: |a,b,c|
-                    v_struct_field(v.visit_struct_field, a, b, c),
-                visit_struct_method: |a,b,c|
-                    v_struct_method(v.visit_struct_method, a, b, c)
-               });
+    return mk_vt(@Visitor {
+        visit_mod: |a,b,c,d,e|v_mod(v.visit_mod, a, b, c, d, e),
+        visit_view_item: |a,b,c| v_view_item(v.visit_view_item, a, b, c),
+        visit_foreign_item:
+            |a,b,c|v_foreign_item(v.visit_foreign_item, a, b, c),
+        visit_item: |a,b,c|v_item(v.visit_item, a, b, c),
+        visit_local: |a,b,c|v_local(v.visit_local, a, b, c),
+        visit_block: |a,b,c|v_block(v.visit_block, a, b, c),
+        visit_stmt: |a,b,c|v_stmt(v.visit_stmt, a, b, c),
+        visit_arm: |a,b,c|v_arm(v.visit_arm, a, b, c),
+        visit_pat: |a,b,c|v_pat(v.visit_pat, a, b, c),
+        visit_decl: |a,b,c|v_decl(v.visit_decl, a, b, c),
+        visit_expr: |a,b,c|v_expr(v.visit_expr, a, b, c),
+        visit_expr_post: |a,b,c| v_expr_post(v.visit_expr_post,
+                                             a, b, c),
+        visit_ty: visit_ty,
+        visit_ty_params: |a,b,c|
+            v_ty_params(v.visit_ty_params, a, b, c),
+        visit_fn: |a,b,c,d,e,f,g|
+            v_fn(v.visit_fn, a, b, c, d, e, f, g),
+        visit_ty_method: |a,b,c|
+            v_ty_method(v.visit_ty_method, a, b, c),
+        visit_trait_method: |a,b,c|
+            v_trait_method(v.visit_trait_method, a, b, c),
+        visit_struct_def: |a,b,c,d,e,f|
+            v_struct_def(v.visit_struct_def, a, b, c, d, e, f),
+        visit_struct_field: |a,b,c|
+            v_struct_field(v.visit_struct_field, a, b, c),
+        visit_struct_method: |a,b,c|
+            v_struct_method(v.visit_struct_method, a, b, c)
+    });
 }
 
 // Local Variables:
diff --git a/src/test/auxiliary/cci_nested_lib.rs b/src/test/auxiliary/cci_nested_lib.rs
index d55302481a9..291a506c4eb 100644
--- a/src/test/auxiliary/cci_nested_lib.rs
+++ b/src/test/auxiliary/cci_nested_lib.rs
@@ -14,7 +14,7 @@
 use dvec::DVec;
 
 type entry<A,B> = {key: A, value: B};
-type alist<A,B> = { eq_fn: fn@(A,A) -> bool, data: DVec<entry<A,B>> };
+struct alist<A,B> { eq_fn: fn@(A,A) -> bool, data: DVec<entry<A,B>> }
 
 fn alist_add<A: Copy, B: Copy>(lst: alist<A,B>, k: A, v: B) {
     lst.data.push({key:k, value:v});
@@ -31,12 +31,12 @@ fn alist_get<A: Copy, B: Copy>(lst: alist<A,B>, k: A) -> B {
 #[inline]
 fn new_int_alist<B: Copy>() -> alist<int, B> {
     fn eq_int(&&a: int, &&b: int) -> bool { a == b }
-    return {eq_fn: eq_int, data: DVec()};
+    return alist {eq_fn: eq_int, data: DVec()};
 }
 
 #[inline]
 fn new_int_alist_2<B: Copy>() -> alist<int, B> {
     #[inline]
     fn eq_int(&&a: int, &&b: int) -> bool { a == b }
-    return {eq_fn: eq_int, data: DVec()};
+    return alist {eq_fn: eq_int, data: DVec()};
 }
diff --git a/src/test/compile-fail/block-coerce-no-2.rs b/src/test/compile-fail/block-coerce-no-2.rs
index 1e539dc4f36..b2265f5e959 100644
--- a/src/test/compile-fail/block-coerce-no-2.rs
+++ b/src/test/compile-fail/block-coerce-no-2.rs
@@ -19,5 +19,5 @@ fn main() {
     }
 
     f(g);
-    //~^ ERROR mismatched types: expected `fn(fn(fn()))`
+    //~^ ERROR mismatched types: expected `extern fn(extern fn(extern fn()))`
 }
diff --git a/src/test/compile-fail/borrowck-autoref-3261.rs b/src/test/compile-fail/borrowck-autoref-3261.rs
index b21114d9222..457cdd23447 100644
--- a/src/test/compile-fail/borrowck-autoref-3261.rs
+++ b/src/test/compile-fail/borrowck-autoref-3261.rs
@@ -9,9 +9,9 @@
 // except according to those terms.
 
 use core::either::*;
-enum X = Either<(uint,uint),fn()>;
+enum X = Either<(uint,uint),extern fn()>;
 impl &X {
-    fn with(blk: fn(x: &Either<(uint,uint),fn()>)) {
+    fn with(blk: fn(x: &Either<(uint,uint),extern fn()>)) {
         blk(&**self)
     }
 }
diff --git a/src/test/compile-fail/main-wrong-type-2.rs b/src/test/compile-fail/main-wrong-type-2.rs
index 4e1989eb25c..bb6633ecdc1 100644
--- a/src/test/compile-fail/main-wrong-type-2.rs
+++ b/src/test/compile-fail/main-wrong-type-2.rs
@@ -9,5 +9,5 @@
 // except according to those terms.
 
 fn main() -> char {
-//~^ ERROR Wrong type in main function: found `fn() -> char`
+//~^ ERROR Wrong type in main function: found `extern fn() -> char`
 }
diff --git a/src/test/compile-fail/main-wrong-type.rs b/src/test/compile-fail/main-wrong-type.rs
index 7f8a4053c43..33d7b913daf 100644
--- a/src/test/compile-fail/main-wrong-type.rs
+++ b/src/test/compile-fail/main-wrong-type.rs
@@ -9,5 +9,5 @@
 // except according to those terms.
 
 fn main(foo: {x: int, y: int}) {
-//~^ ERROR Wrong type in main function: found `fn({x: int,y: int})`
+//~^ ERROR Wrong type in main function: found `extern fn({x: int,y: int})`
 }
diff --git a/src/test/compile-fail/missing-do.rs b/src/test/compile-fail/missing-do.rs
index 3a0e8ffb9c4..916008373c8 100644
--- a/src/test/compile-fail/missing-do.rs
+++ b/src/test/compile-fail/missing-do.rs
@@ -14,6 +14,6 @@ fn foo(f: fn()) { f() }
 
 fn main() {
     ~"" || 42; //~ ERROR binary operation || cannot be applied to type `~str`
-    foo || {}; //~ ERROR binary operation || cannot be applied to type `fn(&fn())`
+    foo || {}; //~ ERROR binary operation || cannot be applied to type `extern fn(&fn())`
     //~^ NOTE did you forget the 'do' keyword for the call?
 }
diff --git a/src/test/run-pass/fn-coerce-field.rs b/src/test/run-pass/fn-coerce-field.rs
index 47f4f122f93..0e7d90e2fd8 100644
--- a/src/test/run-pass/fn-coerce-field.rs
+++ b/src/test/run-pass/fn-coerce-field.rs
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-type r = {
+struct r {
     field: fn@()
-};
+}
 
 fn main() {
     fn f() {}
-    let i: r = {field: f};
+    let i: r = r {field: f};
 }
\ No newline at end of file
diff --git a/src/test/run-pass/intrinsic-frame-address.rs b/src/test/run-pass/intrinsic-frame-address.rs
index 653e84ea347..4b48e9a49c2 100644
--- a/src/test/run-pass/intrinsic-frame-address.rs
+++ b/src/test/run-pass/intrinsic-frame-address.rs
@@ -13,7 +13,7 @@
 #[abi = "rust-intrinsic"]
 extern mod rusti {
     #[legacy_exports];
-    fn frame_address(f: fn(*u8));
+    fn frame_address(f: &once fn(*u8));
 }
 
 fn main() {
diff --git a/src/test/run-pass/issue-1458.rs b/src/test/run-pass/issue-1458.rs
index b87b3d3aa0d..15d809e8208 100644
--- a/src/test/run-pass/issue-1458.rs
+++ b/src/test/run-pass/issue-1458.rs
@@ -12,7 +12,7 @@ fn plus_one(f: fn() -> int) -> int {
   return f() + 1;
 }
 
-fn ret_plus_one() -> fn(fn() -> int) -> int {
+fn ret_plus_one() -> extern fn(fn() -> int) -> int {
   return plus_one;
 }