about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-07-26 14:06:02 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-07-26 14:06:02 +0200
commitaea537779e01359cf8da6944218362d44bfaee83 (patch)
tree235edf688d4fb4928ff766c063dcac779548f34d /src/comp
parente123366bffa69ee3877335b9ca979b0cc301d07c (diff)
downloadrust-aea537779e01359cf8da6944218362d44bfaee83.tar.gz
rust-aea537779e01359cf8da6944218362d44bfaee83.zip
Remove all uses of tuples from the compiler and stdlib
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/metadata/creader.rs19
-rw-r--r--src/comp/metadata/csearch.rs22
-rw-r--r--src/comp/metadata/cstore.rs5
-rw-r--r--src/comp/metadata/decoder.rs44
-rw-r--r--src/comp/metadata/encoder.rs81
-rw-r--r--src/comp/metadata/tydecode.rs36
-rw-r--r--src/comp/middle/alias.rs32
-rw-r--r--src/comp/middle/ast_map.rs8
-rw-r--r--src/comp/middle/freevars.rs4
-rw-r--r--src/comp/middle/resolve.rs84
-rw-r--r--src/comp/middle/trans.rs210
-rw-r--r--src/comp/middle/trans_alt.rs44
-rw-r--r--src/comp/middle/trans_common.rs2
-rw-r--r--src/comp/middle/trans_dps.rs38
-rw-r--r--src/comp/middle/trans_vec.rs10
-rw-r--r--src/comp/middle/tstate/auxiliary.rs74
-rw-r--r--src/comp/middle/tstate/bitvectors.rs2
-rw-r--r--src/comp/middle/tstate/pre_post_conditions.rs26
-rw-r--r--src/comp/middle/tstate/states.rs29
-rw-r--r--src/comp/middle/ty.rs69
-rw-r--r--src/comp/middle/typeck.rs152
-rw-r--r--src/comp/syntax/ast.rs10
-rw-r--r--src/comp/syntax/ext/base.rs3
-rw-r--r--src/comp/syntax/ext/expand.rs4
-rw-r--r--src/comp/syntax/ext/fmt.rs17
-rw-r--r--src/comp/syntax/ext/simplext.rs22
-rw-r--r--src/comp/syntax/parse/eval.rs4
-rw-r--r--src/comp/syntax/parse/lexer.rs18
-rw-r--r--src/comp/syntax/parse/parser.rs81
-rw-r--r--src/comp/util/common.rs6
-rw-r--r--src/comp/util/ppaux.rs5
31 files changed, 590 insertions, 571 deletions
diff --git a/src/comp/metadata/creader.rs b/src/comp/metadata/creader.rs
index 33b160c5c1f..9c26713a0d2 100644
--- a/src/comp/metadata/creader.rs
+++ b/src/comp/metadata/creader.rs
@@ -128,7 +128,7 @@ fn default_native_lib_naming(session::session sess, bool static) ->
 fn find_library_crate(&session::session sess, &ast::ident ident,
                       &(@ast::meta_item)[] metas,
                       &str[] library_search_paths)
-        -> option::t[tup(str, @u8[])] {
+        -> option::t[rec(str ident, @u8[] data)] {
 
     attr::require_unique_names(sess, metas);
 
@@ -161,8 +161,8 @@ fn find_library_crate(&session::session sess, &ast::ident ident,
 
 fn find_library_crate_aux(&rec(str prefix, str suffix) nn, str crate_name,
                           &(@ast::meta_item)[] metas,
-                          &str[] library_search_paths) ->
-                          option::t[tup(str, @u8[])] {
+                          &str[] library_search_paths)
+    -> option::t[rec(str ident, @u8[] data)] {
     let str prefix = nn.prefix + crate_name;
     // FIXME: we could probably use a 'glob' function in std::fs but it will
     // be much easier to write once the unsafe module knows more about FFI
@@ -188,7 +188,7 @@ fn find_library_crate_aux(&rec(str prefix, str suffix) nn, str crate_name,
                         cont;
                     }
                     log #fmt("found %s with matching metadata", path);
-                    ret some(tup(path, cvec));
+                    ret some(rec(ident=path, data=cvec));
                 }
                 case (_) { }
             }
@@ -219,7 +219,8 @@ fn get_metadata_section(str filename) -> option::t[@u8[]] {
 
 fn load_library_crate(&session::session sess, span span,
                       &ast::ident ident, &(@ast::meta_item)[] metas,
-                      &str[] library_search_paths) -> tup(str, @u8[]) {
+                      &str[] library_search_paths)
+    -> rec(str ident, @u8[] data) {
 
     alt (find_library_crate(sess, ident, metas, library_search_paths)) {
         case (some(?t)) {
@@ -237,8 +238,8 @@ fn resolve_crate(env e, ast::ident ident, (@ast::meta_item)[] metas,
         auto cinfo = load_library_crate(e.sess, span, ident, metas,
                                         e.library_search_paths);
 
-        auto cfilename = cinfo._0;
-        auto cdata = cinfo._1;
+        auto cfilename = cinfo.ident;
+        auto cdata = cinfo.data;
 
         // Claim this crate number and cache it
         auto cnum = e.next_crate_num;
@@ -268,8 +269,8 @@ fn resolve_crate_deps(env e, &@u8[] cdata) -> cstore::cnum_map {
     // numbers
     auto cnum_map = new_int_hash[ast::crate_num]();
     for (decoder::crate_dep dep in decoder::get_crate_deps(cdata)) {
-        auto extrn_cnum = dep._0;
-        auto cname = dep._1;
+        auto extrn_cnum = dep.cnum;
+        auto cname = dep.ident;
         log #fmt("resolving dep %s", cname);
         if (e.crate_cache.contains_key(cname)) {
             log "already have it";
diff --git a/src/comp/metadata/csearch.rs b/src/comp/metadata/csearch.rs
index f2f24b9b71f..3519c4ef432 100644
--- a/src/comp/metadata/csearch.rs
+++ b/src/comp/metadata/csearch.rs
@@ -12,17 +12,13 @@ export get_tag_variants;
 export get_type;
 
 fn get_symbol(&cstore::cstore cstore, ast::def_id def) -> str {
-    auto cnum = def._0;
-    auto node_id = def._1;
-    auto cdata = cstore::get_crate_data(cstore, cnum).data;
-    ret decoder::get_symbol(cdata, node_id);
+    auto cdata = cstore::get_crate_data(cstore, def.crate).data;
+    ret decoder::get_symbol(cdata, def.node);
 }
 
 fn get_type_param_count(&cstore::cstore cstore, &ast::def_id def) -> uint {
-    auto cnum = def._0;
-    auto node_id = def._1;
-    auto cdata = cstore::get_crate_data(cstore, cnum).data;
-    ret decoder::get_type_param_count(cdata, node_id);
+    auto cdata = cstore::get_crate_data(cstore, def.crate).data;
+    ret decoder::get_type_param_count(cdata, def.node);
 }
 
 fn lookup_defs(&cstore::cstore cstore, ast::crate_num cnum,
@@ -33,7 +29,7 @@ fn lookup_defs(&cstore::cstore cstore, ast::crate_num cnum,
 
 fn get_tag_variants(ty::ctxt tcx, ast::def_id def) -> ty::variant_info[] {
     auto cstore = tcx.sess.get_cstore();
-    auto cnum = def._0;
+    auto cnum = def.crate;
     auto cdata = cstore::get_crate_data(cstore, cnum).data;
     auto resolver = bind translate_def_id(tcx.sess, cnum, _);
     ret decoder::get_tag_variants(cdata, def, tcx, resolver)
@@ -41,7 +37,7 @@ fn get_tag_variants(ty::ctxt tcx, ast::def_id def) -> ty::variant_info[] {
 
 fn get_type(ty::ctxt tcx, ast::def_id def) -> ty::ty_param_count_and_ty {
     auto cstore = tcx.sess.get_cstore();
-    auto cnum = def._0;
+    auto cnum = def.crate;
     auto cdata = cstore::get_crate_data(cstore, cnum).data;
     auto resolver = bind translate_def_id(tcx.sess, cnum, _);
     decoder::get_type(cdata, def, tcx, resolver)
@@ -56,8 +52,8 @@ fn translate_def_id(&session::session sess,
                     ast::crate_num searched_crate,
                     &ast::def_id def_id) -> ast::def_id {
 
-    auto ext_cnum = def_id._0;
-    auto node_id = def_id._1;
+    auto ext_cnum = def_id.crate;
+    auto node_id = def_id.node;
 
     assert searched_crate != ast::local_crate;
     assert ext_cnum != ast::local_crate;
@@ -72,7 +68,7 @@ fn translate_def_id(&session::session sess,
         }
     };
 
-    ret tup(local_cnum, node_id);
+    ret rec(crate=local_cnum, node=node_id);
 }
 
 // Local Variables:
diff --git a/src/comp/metadata/cstore.rs b/src/comp/metadata/cstore.rs
index 7f150c088b1..875eeba6ce4 100644
--- a/src/comp/metadata/cstore.rs
+++ b/src/comp/metadata/cstore.rs
@@ -78,8 +78,9 @@ fn have_crate_data(&cstore cstore, ast::crate_num cnum) -> bool {
     ret p(cstore).metas.contains_key(cnum);
 }
 
-iter iter_crate_data(&cstore cstore) -> @tup(ast::crate_num, crate_metadata) {
-    for each (@tup(ast::crate_num, crate_metadata) kv
+iter iter_crate_data(&cstore cstore)
+    -> @rec(ast::crate_num key, crate_metadata val) {
+    for each (@rec(ast::crate_num key, crate_metadata val) kv
               in p(cstore).metas.items()) {
         put kv;
     }
diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs
index 14c69503175..90176a4c3e9 100644
--- a/src/comp/metadata/decoder.rs
+++ b/src/comp/metadata/decoder.rs
@@ -102,8 +102,8 @@ fn item_type(&ebmlivec::doc item, ast::crate_num this_cnum,
 
         // This item was defined in the crate we're searching if it's has the
         // local crate number, otherwise we need to search a different crate
-        if (external_def_id._0 == ast::local_crate) {
-            ret tup(this_cnum, external_def_id._1);
+        if (external_def_id.crate == ast::local_crate) {
+            ret rec(crate=this_cnum, node=external_def_id.node);
         } else {
             ret extres(external_def_id);
         }
@@ -118,7 +118,7 @@ fn item_ty_param_count(&ebmlivec::doc item) -> uint {
     let uint ty_param_count = 0u;
     auto tp = tag_items_data_item_ty_param_count;
     for each (ebmlivec::doc p in ebmlivec::tagged_docs(item, tp)) {
-        ty_param_count = ebmlivec::vint_at(ebmlivec::doc_data(p), 0u)._0;
+        ty_param_count = ebmlivec::vint_at(ebmlivec::doc_data(p), 0u).val;
     }
     ret ty_param_count;
 }
@@ -129,7 +129,7 @@ fn tag_variant_ids(&ebmlivec::doc item,
     auto v = tag_items_data_item_variant;
     for each (ebmlivec::doc p in ebmlivec::tagged_docs(item, v)) {
         auto ext = parse_def_id(ebmlivec::doc_data(p));
-        ids += ~[tup(this_cnum, ext._1)];
+        ids += ~[rec(crate=this_cnum, node=ext.node)];
     }
     ret ids;
 }
@@ -162,9 +162,9 @@ fn lookup_defs(&@u8[] data, ast::crate_num cnum, &ast::ident[] path)
 // FIXME doesn't yet handle re-exported externals
 fn lookup_def(ast::crate_num cnum, @u8[] data, &ast::def_id did_)
         -> ast::def {
-    auto item = lookup_item(did_._1, data);
+    auto item = lookup_item(did_.node, data);
     auto kind_ch = item_kind(item);
-    auto did = tup(cnum, did_._1);
+    auto did = rec(crate=cnum, node=did_.node);
     auto def =
         alt (kind_ch as char) {
             case ('c') { ast::def_const(did) }
@@ -179,7 +179,7 @@ fn lookup_def(ast::crate_num cnum, @u8[] data, &ast::def_id did_)
             case ('n') { ast::def_native_mod(did) }
             case ('v') {
                 auto tid = variant_tag_id(item);
-                tid = tup(cnum, tid._1);
+                tid = rec(crate=cnum, node=tid.node);
                 ast::def_variant(tid, did)
             }
         };
@@ -188,8 +188,8 @@ fn lookup_def(ast::crate_num cnum, @u8[] data, &ast::def_id did_)
 
 fn get_type(@u8[] data, ast::def_id def, &ty::ctxt tcx,
             &external_resolver extres) -> ty::ty_param_count_and_ty {
-    auto this_cnum = def._0;
-    auto node_id = def._1;
+    auto this_cnum = def.crate;
+    auto node_id = def.node;
     auto item = lookup_item(node_id, data);
     auto t = item_type(item, this_cnum, tcx, extres);
     auto tp_count;
@@ -198,7 +198,7 @@ fn get_type(@u8[] data, ast::def_id def, &ty::ctxt tcx,
     if (has_ty_params) {
         tp_count = item_ty_param_count(item);
     } else { tp_count = 0u; }
-    ret tup(tp_count, t);
+    ret rec(count=tp_count, ty=t);
 }
 
 fn get_type_param_count(@u8[] data, ast::node_id id) -> uint {
@@ -212,15 +212,15 @@ fn get_symbol(@u8[] data, ast::node_id id) -> str {
 fn get_tag_variants(&@u8[] data, ast::def_id def,
                     &ty::ctxt tcx,
                     &external_resolver extres) -> ty::variant_info[] {
-    auto external_crate_id = def._0;
+    auto external_crate_id = def.crate;
     auto data = cstore::get_crate_data(tcx.sess.get_cstore(),
                                        external_crate_id).data;
     auto items = ebmlivec::get_doc(ebmlivec::new_doc(data), tag_items);
-    auto item = find_item(def._1, items);
+    auto item = find_item(def.node, items);
     let ty::variant_info[] infos = ~[];
     auto variant_ids = tag_variant_ids(item, external_crate_id);
     for (ast::def_id did in variant_ids) {
-        auto item = find_item(did._1, items);
+        auto item = find_item(did.node, items);
         auto ctor_ty = item_type(item, external_crate_id, tcx, extres);
         let ty::t[] arg_tys = ~[];
         alt (ty::struct(tcx, ctor_ty)) {
@@ -252,17 +252,17 @@ fn kind_has_type_params(u8 kind_ch) -> bool {
         };
 }
 
-fn read_path(&ebmlivec::doc d) -> tup(str, uint) {
+fn read_path(&ebmlivec::doc d) -> rec(str path, uint pos) {
     auto desc = ebmlivec::doc_data(d);
     auto pos = ebmlivec::be_uint_from_bytes(@desc, 0u, 4u);
     auto pathbytes = ivec::slice[u8](desc, 4u, ivec::len[u8](desc));
     auto path = str::unsafe_from_bytes_ivec(pathbytes);
-    ret tup(path, pos);
+    ret rec(path=path, pos=pos);
 }
 
 fn describe_def(&ebmlivec::doc items, ast::def_id id) -> str {
-    if (id._0 != 0) { ret "external"; }
-    ret item_kind_to_str(item_kind(find_item(id._1, items)));
+    if (id.crate != ast::local_crate) { ret "external"; }
+    ret item_kind_to_str(item_kind(find_item(id.node, items)));
 }
 
 fn item_kind_to_str(u8 kind) -> str {
@@ -349,7 +349,7 @@ fn get_crate_attributes(@u8[] data) -> ast::attribute[] {
     ret get_attributes(ebmlivec::new_doc(data));
 }
 
-type crate_dep = tup(ast::crate_num, str);
+type crate_dep = rec(ast::crate_num cnum, str ident);
 
 fn get_crate_deps(@u8[] data) -> crate_dep[] {
     let crate_dep[] deps = ~[];
@@ -360,7 +360,7 @@ fn get_crate_deps(@u8[] data) -> crate_dep[] {
               ebmlivec::tagged_docs(depsdoc, tag_crate_dep)) {
         auto depname =
             str::unsafe_from_bytes_ivec(ebmlivec::doc_data(depdoc));
-        deps += ~[tup(crate_num, depname)];
+        deps += ~[rec(cnum=crate_num, ident=depname)];
         crate_num += 1;
     }
     ret deps;
@@ -370,7 +370,7 @@ fn list_crate_deps(@u8[] data, ioivec::writer out) {
     out.write_str("=External Dependencies=\n");
 
     for (crate_dep dep in get_crate_deps(data)) {
-        out.write_str(#fmt("%d %s\n", dep._0, dep._1));
+        out.write_str(#fmt("%d %s\n", dep.cnum, dep.ident));
     }
 
     out.write_str("\n");
@@ -387,10 +387,10 @@ fn list_crate_items(&@u8[] bytes, &ebmlivec::doc md, ioivec::writer out) {
         auto et = tag_index_buckets_bucket_elt;
         for each (ebmlivec::doc elt in ebmlivec::tagged_docs(bucket, et)) {
             auto data = read_path(elt);
-            auto def = ebmlivec::doc_at(bytes, data._1);
+            auto def = ebmlivec::doc_at(bytes, data.pos);
             auto did_doc = ebmlivec::get_doc(def, tag_def_id);
             auto did = parse_def_id(ebmlivec::doc_data(did_doc));
-            out.write_str(#fmt("%s (%s)\n", data._0,
+            out.write_str(#fmt("%s (%s)\n", data.path,
                                describe_def(items, did)));
         }
     }
diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs
index 0aa9fcbeb72..042ec6a9932 100644
--- a/src/comp/metadata/encoder.rs
+++ b/src/comp/metadata/encoder.rs
@@ -37,9 +37,11 @@ fn encode_def_id(&ebmlivec::writer ebml_w, &def_id id) {
     ebmlivec::end_tag(ebml_w);
 }
 
+type entry[T] = rec(T val, uint pos);
+
 fn encode_tag_variant_paths(&ebmlivec::writer ebml_w, &variant[] variants,
                             &str[] path,
-                            &mutable (tup(str, uint))[] index) {
+                            &mutable (entry[str])[] index) {
     for (variant variant in variants) {
         add_to_index(ebml_w, path, index, variant.node.name);
         ebmlivec::start_tag(ebml_w, tag_paths_data_item);
@@ -50,14 +52,15 @@ fn encode_tag_variant_paths(&ebmlivec::writer ebml_w, &variant[] variants,
 }
 
 fn add_to_index(&ebmlivec::writer ebml_w, &str[] path,
-                &mutable (tup(str, uint))[] index, &str name) {
+                &mutable (entry[str])[] index, &str name) {
     auto full_path = path + ~[name];
-    index += ~[tup(str::connect_ivec(full_path, "::"), ebml_w.writer.tell())];
+    index += ~[rec(val=str::connect_ivec(full_path, "::"),
+                   pos=ebml_w.writer.tell())];
 }
 
-fn encode_native_module_item_paths(&ebmlivec::writer ebml_w,
-                                   &native_mod nmod, &str[] path,
-                                   &mutable (tup(str, uint))[] index) {
+fn encode_native_module_item_paths
+    (&ebmlivec::writer ebml_w, &native_mod nmod, &str[] path,
+     &mutable (entry[str])[] index) {
     for (@native_item nitem in nmod.items) {
         add_to_index(ebml_w, path, index, nitem.ident);
         ebmlivec::start_tag(ebml_w, tag_paths_data_item);
@@ -69,7 +72,7 @@ fn encode_native_module_item_paths(&ebmlivec::writer ebml_w,
 
 fn encode_module_item_paths(&ebmlivec::writer ebml_w, &_mod module,
                             &str[] path,
-                            &mutable (tup(str, uint))[] index) {
+                            &mutable (entry[str])[] index) {
     for (@item it in module.items) {
         if (!is_exported(it.ident, module)) { cont; }
         alt (it.node) {
@@ -149,8 +152,8 @@ fn encode_module_item_paths(&ebmlivec::writer ebml_w, &_mod module,
 }
 
 fn encode_item_paths(&ebmlivec::writer ebml_w, &@crate crate)
-        -> (tup(str, uint))[] {
-    let (tup(str, uint))[] index = ~[];
+        -> (entry[str])[] {
+    let (entry[str])[] index = ~[];
     let str[] path = ~[];
     ebmlivec::start_tag(ebml_w, tag_paths);
     encode_module_item_paths(ebml_w, crate.node.module, path, index);
@@ -166,7 +169,7 @@ fn encode_kind(&ebmlivec::writer ebml_w, u8 c) {
     ebmlivec::end_tag(ebml_w);
 }
 
-fn def_to_str(&def_id did) -> str { ret #fmt("%d:%d", did._0, did._1); }
+fn def_to_str(&def_id did) -> str { ret #fmt("%d:%d", did.crate, did.node); }
 
 fn encode_type_param_count(&ebmlivec::writer ebml_w, &ty_param[] tps) {
     ebmlivec::start_tag(ebml_w, tag_items_data_item_ty_param_count);
@@ -212,10 +215,10 @@ fn encode_tag_id(&ebmlivec::writer ebml_w, &def_id id) {
 
 fn encode_tag_variant_info(&@encode_ctxt ecx, &ebmlivec::writer ebml_w,
                            node_id id, &variant[] variants,
-                           &mutable (tup(int, uint))[] index,
+                           &mutable (entry[int])[] index,
                            &ty_param[] ty_params) {
     for (variant variant in variants) {
-        index += ~[tup(variant.node.id, ebml_w.writer.tell())];
+        index += ~[rec(val=variant.node.id, pos=ebml_w.writer.tell())];
         ebmlivec::start_tag(ebml_w, tag_items_data_item);
         encode_def_id(ebml_w, local_def(variant.node.id));
         encode_kind(ebml_w, 'v' as u8);
@@ -232,7 +235,7 @@ fn encode_tag_variant_info(&@encode_ctxt ecx, &ebmlivec::writer ebml_w,
 }
 
 fn encode_info_for_item(@encode_ctxt ecx, &ebmlivec::writer ebml_w,
-                        @item item, &mutable (tup(int, uint))[] index) {
+                        @item item, &mutable (entry[int])[] index) {
     alt (item.node) {
         case (item_const(_, _)) {
             ebmlivec::start_tag(ebml_w, tag_items_data_item);
@@ -301,7 +304,7 @@ fn encode_info_for_item(@encode_ctxt ecx, &ebmlivec::writer ebml_w,
             encode_symbol(ecx, ebml_w, item.id);
             ebmlivec::end_tag(ebml_w);
 
-            index += ~[tup(ctor_id, ebml_w.writer.tell())];
+            index += ~[rec(val=ctor_id, pos=ebml_w.writer.tell())];
             ebmlivec::start_tag(ebml_w, tag_items_data_item);
             encode_def_id(ebml_w, local_def(ctor_id));
             encode_kind(ebml_w, 'f' as u8);
@@ -320,7 +323,7 @@ fn encode_info_for_item(@encode_ctxt ecx, &ebmlivec::writer ebml_w,
             encode_type(ecx, ebml_w, ty::ty_fn_ret(ecx.ccx.tcx, fn_ty));
             ebmlivec::end_tag(ebml_w);
 
-            index += ~[tup(ctor_id, ebml_w.writer.tell())];
+            index += ~[rec(val=ctor_id, pos=ebml_w.writer.tell())];
             ebmlivec::start_tag(ebml_w, tag_items_data_item);
             encode_def_id(ebml_w, local_def(ctor_id));
             encode_kind(ebml_w, 'f' as u8);
@@ -355,18 +358,18 @@ fn encode_info_for_native_item(&@encode_ctxt ecx, &ebmlivec::writer ebml_w,
 }
 
 fn encode_info_for_items(&@encode_ctxt ecx, &ebmlivec::writer ebml_w)
-        -> (tup(int, uint))[] {
-    let (tup(int, uint))[] index = ~[];
+        -> (entry[int])[] {
+    let (entry[int])[] index = ~[];
     ebmlivec::start_tag(ebml_w, tag_items_data);
-    for each (@tup(node_id, middle::ast_map::ast_node) kvp in
-              ecx.ccx.ast_map.items()) {
-        alt (kvp._1) {
+    for each (@rec(node_id key, middle::ast_map::ast_node val) kvp
+              in ecx.ccx.ast_map.items()) {
+        alt (kvp.val) {
             case (middle::ast_map::node_item(?i)) {
-                index += ~[tup(kvp._0, ebml_w.writer.tell())];
+                index += ~[rec(val=kvp.key, pos=ebml_w.writer.tell())];
                 encode_info_for_item(ecx, ebml_w, i, index);
             }
             case (middle::ast_map::node_native_item(?i)) {
-                index += ~[tup(kvp._0, ebml_w.writer.tell())];
+                index += ~[rec(val=kvp.key, pos=ebml_w.writer.tell())];
                 encode_info_for_native_item(ecx, ebml_w, i);
             }
             case (_) {}
@@ -379,35 +382,35 @@ fn encode_info_for_items(&@encode_ctxt ecx, &ebmlivec::writer ebml_w)
 
 // Path and definition ID indexing
 
-fn create_index[T](&(tup(T, uint))[] index, fn(&T) -> uint  hash_fn)
-        -> (@(tup(T, uint))[])[] {
-    let (@mutable (tup(T,uint))[])[] buckets = ~[];
+fn create_index[T](&(entry[T])[] index, fn(&T) -> uint  hash_fn)
+        -> (@(entry[T])[])[] {
+    let (@mutable (entry[T])[])[] buckets = ~[];
     for each (uint i in uint::range(0u, 256u)) { buckets += ~[@mutable ~[]]; }
-    for (tup(T, uint) elt in index) {
-        auto h = hash_fn(elt._0);
+    for (entry[T] elt in index) {
+        auto h = hash_fn(elt.val);
         *(buckets.(h % 256u)) += ~[elt];
     }
 
     auto buckets_frozen = ~[];
-    for (@mutable (tup(T, uint))[] bucket in buckets) {
+    for (@mutable (entry[T])[] bucket in buckets) {
         buckets_frozen += ~[@*bucket];
     }
     ret buckets_frozen;
 }
 
-fn encode_index[T](&ebmlivec::writer ebml_w, &(@(tup(T, uint))[])[] buckets,
+fn encode_index[T](&ebmlivec::writer ebml_w, &(@(entry[T])[])[] buckets,
                    fn(&ioivec::writer, &T)  write_fn) {
     auto writer = ioivec::new_writer_(ebml_w.writer);
     ebmlivec::start_tag(ebml_w, tag_index);
     let uint[] bucket_locs = ~[];
     ebmlivec::start_tag(ebml_w, tag_index_buckets);
-    for (@(tup(T, uint))[] bucket in buckets) {
+    for (@(entry[T])[] bucket in buckets) {
         bucket_locs += ~[ebml_w.writer.tell()];
         ebmlivec::start_tag(ebml_w, tag_index_buckets_bucket);
-        for (tup(T, uint) elt in *bucket) {
+        for (entry[T] elt in *bucket) {
             ebmlivec::start_tag(ebml_w, tag_index_buckets_bucket_elt);
-            writer.write_be_uint(elt._1, 4u);
-            write_fn(writer, elt._0);
+            writer.write_be_uint(elt.pos, 4u);
+            write_fn(writer, elt.val);
             ebmlivec::end_tag(ebml_w);
         }
         ebmlivec::end_tag(ebml_w);
@@ -527,28 +530,28 @@ fn synthesize_crate_attrs(&@encode_ctxt ecx,
 fn encode_crate_deps(&ebmlivec::writer ebml_w, &cstore::cstore cstore) {
 
     fn get_ordered_names(&cstore::cstore cstore) -> str[] {
-        type hashkv = @tup(crate_num, cstore::crate_metadata);
-        type numname = tup(crate_num, str);
+        type hashkv = @rec(crate_num key, cstore::crate_metadata val);
+        type numname = rec(crate_num crate, str ident);
 
         // Pull the cnums and names out of cstore
         let numname[mutable] pairs = ~[mutable];
         for each (hashkv hashkv in cstore::iter_crate_data(cstore)) {
-            pairs += ~[mutable tup(hashkv._0, hashkv._1.name)];
+            pairs += ~[mutable rec(crate=hashkv.key, ident=hashkv.val.name)];
         }
 
         // Sort by cnum
-        fn lteq(&numname kv1, &numname kv2) -> bool { kv1._0 <= kv2._0 }
+        fn lteq(&numname kv1, &numname kv2) -> bool { kv1.crate <= kv2.crate }
         std::sort::ivector::quick_sort(lteq, pairs);
 
         // Sanity-check the crate numbers
         auto expected_cnum = 1;
         for (numname n in pairs) {
-            assert n._0 == expected_cnum;
+            assert n.crate == expected_cnum;
             expected_cnum += 1;
         }
 
         // Return just the names
-        fn name(&numname kv) -> str { kv._1 }
+        fn name(&numname kv) -> str { kv.ident }
         // mutable -> immutable hack for ivec::map
         auto immpairs = ivec::slice(pairs, 0u, ivec::len(pairs));
         ret ivec::map(name, immpairs);
diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs
index 4992dc8871a..e4a79e08add 100644
--- a/src/comp/metadata/tydecode.rs
+++ b/src/comp/metadata/tydecode.rs
@@ -249,13 +249,13 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
         }
         case ('F') {
             auto func = parse_ty_fn(st, sd);
-            ret ty::mk_fn(st.tcx, ast::proto_fn, func._0, func._1, func._2,
-                          func._3);
+            ret ty::mk_fn(st.tcx, ast::proto_fn, func.args, func.ty, func.cf,
+                          func.cs);
         }
         case ('W') {
             auto func = parse_ty_fn(st, sd);
-            ret ty::mk_fn(st.tcx, ast::proto_iter, func._0, func._1, func._2,
-                          func._3);
+            ret ty::mk_fn(st.tcx, ast::proto_iter, func.args, func.ty,
+                          func.cf, func.cs);
         }
         case ('N') {
             auto abi;
@@ -267,7 +267,7 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
                 case ('s') { abi = ast::native_abi_x86stdcall; }
             }
             auto func = parse_ty_fn(st, sd);
-            ret ty::mk_native_fn(st.tcx, abi, func._0, func._1);
+            ret ty::mk_native_fn(st.tcx, abi, func.args, func.ty);
         }
         case ('O') {
             assert (next(st) as char == '[');
@@ -286,10 +286,10 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
                 methods +=
                     ~[rec(proto=proto,
                           ident=name,
-                          inputs=func._0,
-                          output=func._1,
-                          cf=func._2,
-                          constrs=func._3)];
+                          inputs=func.args,
+                          output=func.ty,
+                          cf=func.cf,
+                          constrs=func.cs)];
             }
             st.pos += 1u;
             ret ty::mk_obj(st.tcx, methods);
@@ -314,12 +314,13 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
             assert (next(st) as char == ':');
             auto len = parse_hex(st);
             assert (next(st) as char == '#');
-            alt (st.tcx.rcache.find(tup(st.crate, pos, len))) {
+            alt (st.tcx.rcache.find(rec(cnum=st.crate, pos=pos, len=len))) {
                 case (some(?tt)) { ret tt; }
                 case (none) {
                     auto ps = @rec(pos=pos, len=len with *st);
                     auto tt = parse_ty(ps, sd);
-                    st.tcx.rcache.insert(tup(st.crate, pos, len), tt);
+                    st.tcx.rcache.insert(rec(cnum=st.crate, pos=pos, len=len),
+                                         tt);
                     ret tt;
                 }
             }
@@ -385,7 +386,7 @@ fn parse_hex(@pstate st) -> uint {
 }
 
 fn parse_ty_fn(@pstate st, str_def sd) ->
-   tup(ty::arg[], ty::t, ast::controlflow, (@ty::constr)[]) {
+    rec(ty::arg[] args, ty::t ty, ast::controlflow cf, (@ty::constr)[] cs) {
     assert (next(st) as char == '[');
     let ty::arg[] inputs = ~[];
     while (peek(st) as char != ']') {
@@ -404,9 +405,12 @@ fn parse_ty_fn(@pstate st, str_def sd) ->
     auto cs = parse_constrs(st, sd);
     alt (parse_ty_or_bang(st, sd)) {
         case (a_bang) {
-            ret tup(inputs, ty::mk_bot(st.tcx), ast::noreturn, cs);
+            ret rec(args=inputs, ty=ty::mk_bot(st.tcx),
+                    cf=ast::noreturn, cs=cs);
+        }
+        case (a_ty(?t)) {
+          ret rec(args=inputs, ty=t, cf=ast::return, cs=cs);
         }
-        case (a_ty(?t)) { ret tup(inputs, t, ast::return, cs); }
     }
 }
 
@@ -431,8 +435,8 @@ fn parse_def_id(&u8[] buf) -> ast::def_id {
     for (u8 b in def_part) { def_part_vec += [b]; }
 
     auto crate_num = uint::parse_buf(crate_part_vec, 10u) as int;
-    auto def_id = uint::parse_buf(def_part_vec, 10u) as int;
-    ret tup(crate_num, def_id);
+    auto def_num = uint::parse_buf(def_part_vec, 10u) as int;
+    ret rec(crate=crate_num, node=def_num);
 }
 
 //
diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs
index c6c70b464d9..632b18d26b1 100644
--- a/src/comp/middle/alias.rs
+++ b/src/comp/middle/alias.rs
@@ -154,7 +154,7 @@ fn check_call(&ctx cx, &@ast::expr f, &(@ast::expr)[] args, &scope sc) ->
     auto fty = ty::expr_ty(cx.tcx, f);
     auto arg_ts = fty_args(cx, fty);
     let node_id[] roots = ~[];
-    let tup(uint, node_id)[] mut_roots = ~[];
+    let rec(uint arg, node_id node)[] mut_roots = ~[];
     let ty::t[] unsafe_ts = ~[];
     let uint[] unsafe_t_offsets = ~[];
     auto i = 0u;
@@ -164,7 +164,7 @@ fn check_call(&ctx cx, &@ast::expr f, &(@ast::expr)[] args, &scope sc) ->
             auto root = expr_root(cx, arg, false);
             if (arg_t.mode == ty::mo_alias(true)) {
                 alt (path_def_id(cx, arg)) {
-                  some(?did) { mut_roots += ~[tup(i, did._1)]; }
+                  some(?did) { mut_roots += ~[rec(arg=i, node=did.node)]; }
                   _ {
                     if (!mut_field(root.ds)) {
                         auto m = "passing a temporary value or \
@@ -175,7 +175,7 @@ fn check_call(&ctx cx, &@ast::expr f, &(@ast::expr)[] args, &scope sc) ->
                 }
             }
             alt (path_def_id(cx, root.ex)) {
-              some(?did) { roots += ~[did._1]; }
+              some(?did) { roots += ~[did.node]; }
               _ { }
             }
             alt (inner_mut(root.ds)) {
@@ -221,11 +221,11 @@ fn check_call(&ctx cx, &@ast::expr f, &(@ast::expr)[] args, &scope sc) ->
     }
     // Ensure we're not passing a root by mutable alias.
 
-    for (tup(uint, node_id) root in mut_roots) {
+    for (rec(uint arg, node_id node) root in mut_roots) {
         auto mut_alias_to_root = false;
         auto mut_alias_to_root_count = 0u;
         for (node_id r in roots) {
-            if root._1 == r {
+            if root.node == r {
                 mut_alias_to_root_count += 1u;
                 if mut_alias_to_root_count > 1u {
                     mut_alias_to_root = true;
@@ -235,7 +235,7 @@ fn check_call(&ctx cx, &@ast::expr f, &(@ast::expr)[] args, &scope sc) ->
         }
 
         if (mut_alias_to_root) {
-            cx.tcx.sess.span_err(args.(root._0).span,
+            cx.tcx.sess.span_err(args.(root.arg).span,
                                  "passing a mutable alias to a \
                  variable that roots another alias");
         }
@@ -257,7 +257,7 @@ fn check_tail_call(&ctx cx, &@ast::expr call) {
             alt (args.(i).node) {
                 case (ast::expr_path(_)) {
                     auto def = cx.tcx.def_map.get(args.(i).id);
-                    auto dnum = ast::def_id_of_def(def)._1;
+                    auto dnum = ast::def_id_of_def(def).node;
                     alt (cx.local_map.find(dnum)) {
                         case (some(arg(ast::alias(?mut)))) {
                             if (mut_a && !mut) {
@@ -286,7 +286,7 @@ fn check_alt(&ctx cx, &@ast::expr input, &ast::arm[] arms, &scope sc,
     visit::visit_expr(input, sc, v);
     auto root = expr_root(cx, input, true);
     auto roots = alt (path_def_id(cx, root.ex)) {
-      some(?did) { ~[did._1] }
+      some(?did) { ~[did.node] }
       _ { ~[] }
     };
     let ty::t[] forbidden_tp =
@@ -350,7 +350,7 @@ fn check_for(&ctx cx, &@ast::local local, &@ast::expr seq, &ast::blk blk,
     auto defnum = local.node.id;
     auto root = expr_root(cx, seq, false);
     auto root_def = alt (path_def_id(cx, root.ex)) {
-      some(?did) { ~[did._1] }
+      some(?did) { ~[did.node] }
       _ { ~[] }
     };
     auto unsafe = alt (inner_mut(root.ds)) { some(?t) { ~[t] } _ { ~[] } };
@@ -381,7 +381,7 @@ fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::node_id id,
              bool assign, &scope sc) {
     auto def = cx.tcx.def_map.get(id);
     if (!def_is_local(def, true)) { ret; }
-    auto my_defnum = ast::def_id_of_def(def)._1;
+    auto my_defnum = ast::def_id_of_def(def).node;
     auto var_t = ty::expr_ty(cx.tcx, ex);
     for (restrict r in *sc) {
         // excludes variables introduced since the alias was made
@@ -400,7 +400,7 @@ fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::node_id id,
 fn check_lval(&@ctx cx, &@ast::expr dest, &scope sc, &vt[scope] v) {
     alt (dest.node) {
         case (ast::expr_path(?p)) {
-            auto dnum = ast::def_id_of_def(cx.tcx.def_map.get(dest.id))._1;
+            auto dnum = ast::def_id_of_def(cx.tcx.def_map.get(dest.id)).node;
             if (is_immutable_alias(cx, sc, dnum)) {
                 cx.tcx.sess.span_err(dest.span,
                                      "assigning to immutable alias");
@@ -488,15 +488,15 @@ fn test_scope(&ctx cx, &scope sc, &restrict r, &ast::path p) {
         auto msg =
             alt (prob) {
                 case (overwritten(?sp, ?wpt)) {
-                    tup(sp, "overwriting " + ast::path_name(wpt))
+                    rec(span=sp, msg="overwriting " + ast::path_name(wpt))
                 }
                 case (val_taken(?sp, ?vpt)) {
-                    tup(sp, "taking the value of " + ast::path_name(vpt))
+                    rec(span=sp, msg="taking the value of " +
+                        ast::path_name(vpt))
                 }
             };
-        cx.tcx.sess.span_err(msg._0,
-                             msg._1 + " will invalidate alias " +
-                                 ast::path_name(p) + ", which is still used");
+        cx.tcx.sess.span_err(msg.span, msg.msg + " will invalidate alias " +
+                             ast::path_name(p) + ", which is still used");
     }
 }
 
diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs
index 78f99f75f18..3e47cd0cec0 100644
--- a/src/comp/middle/ast_map.rs
+++ b/src/comp/middle/ast_map.rs
@@ -91,14 +91,14 @@ fn new_smallintmap_adapter[K, V](fn(&K) -> uint key_idx,
 
         fn rehash() { fail }
 
-        iter items() -> @tup(K, V) {
+        iter items() -> @rec(K key, V val) {
             auto idx = 0u;
             for (option::t[V] item in map.v) {
                 alt (item) {
                     case (option::some(?elt)) {
                         auto value = elt;
                         auto key = idx_key(idx);
-                        put @tup(key, value);
+                        put @rec(key=key, val=value);
                     }
                     case (option::none) { }
                 }
@@ -106,8 +106,8 @@ fn new_smallintmap_adapter[K, V](fn(&K) -> uint key_idx,
             }
         }
         iter keys() -> K {
-            for each (@tup(K, V) p in self.items()) {
-                put p._0;
+            for each (@rec(K key, V val) p in self.items()) {
+                put p.key;
             }
         }
     }
diff --git a/src/comp/middle/freevars.rs b/src/comp/middle/freevars.rs
index 2b733e7ba50..5d17bea86ea 100644
--- a/src/comp/middle/freevars.rs
+++ b/src/comp/middle/freevars.rs
@@ -96,7 +96,7 @@ fn collect_freevars(&resolve::def_map def_map, &session::session sess,
     auto defs = new_int_hash();
     for (ast::node_id ref_id_ in e.refs) {
         auto ref_id = ref_id_;
-        auto def_id = ast::def_id_of_def(def_map.get(ref_id))._1;
+        auto def_id = ast::def_id_of_def(def_map.get(ref_id)).node;
         if !decls.contains_key(def_id) {
             uses += ~[ref_id];
             set_add(defs, def_id);
@@ -172,7 +172,7 @@ fn def_lookup(&ty::ctxt tcx, ast::node_id f, ast::node_id id) ->
       none { ret none; }
       some(?d) {
         auto did = ast::def_id_of_def(d);
-        if is_freevar_of(tcx, did._1, f) {
+        if is_freevar_of(tcx, did.node, f) {
             ret some(ast::def_upvar(did, @d));
         } else { ret some(d); }
       }
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index d50d5a54bdb..eb9a52c2d53 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -66,23 +66,24 @@ tag import_state {
              option::t[def]); /* module */
 }
 
-type ext_hash = hashmap[tup(def_id, str, namespace), def];
+type ext_hash = hashmap[rec(def_id did, str ident, namespace ns), def];
 
 fn new_ext_hash() -> ext_hash {
-    fn hash(&tup(def_id, str, namespace) v) -> uint {
-        ret str::hash(v._1) + util::common::hash_def(v._0) +
-                alt (v._2) {
+    type key = rec(def_id did, str ident, namespace ns);
+    fn hash(&key v) -> uint {
+        ret str::hash(v.ident) + util::common::hash_def(v.did) +
+                alt (v.ns) {
                     case (ns_value) { 1u }
                     case (ns_type) { 2u }
                     case (ns_module) { 3u }
                 };
     }
-    fn eq(&tup(def_id, str, namespace) v1, &tup(def_id, str, namespace) v2) ->
+    fn eq(&key v1, &key v2) ->
        bool {
-        ret util::common::def_eq(v1._0, v2._0) && str::eq(v1._1, v2._1) &&
-                v1._2 == v2._2;
+        ret util::common::def_eq(v1.did, v2.did) &&
+            str::eq(v1.ident, v2.ident) && v1.ns == v2.ns;
     }
-    ret std::map::mk_hashmap[tup(def_id, str, namespace), def](hash, eq);
+    ret std::map::mk_hashmap[key, def](hash, eq);
 }
 
 tag mod_index_entry {
@@ -95,7 +96,7 @@ tag mod_index_entry {
 type mod_index = hashmap[ident, list[mod_index_entry]];
 
 // A tuple of an imported def and the import stmt that brung it
-type glob_imp_def = tup(def, @ast::view_item);
+type glob_imp_def = rec(def def, @ast::view_item item);
 
 type indexed_mod =
     rec(option::t[ast::_mod] m,
@@ -117,7 +118,7 @@ type env =
         hashmap[ast::node_id, @indexed_mod] mod_map,
         hashmap[def_id, ident[]] ext_map,
         ext_hash ext_cache,
-        mutable tup(str, scope)[] reported,
+        mutable rec(str ident, scope sc)[] reported,
         session sess);
 
 
@@ -226,7 +227,7 @@ fn map_crate(&@env e, &@ast::crate c) {
                 auto imp = follow_import(*e, sc, path, vi.span);
                 if (option::is_some(imp)) {
                     find_mod(e, sc).glob_imports +=
-                        ~[tup(option::get(imp), vi)];
+                        ~[rec(def=option::get(imp), item=vi)];
                 }
             }
             case (_) { }
@@ -235,8 +236,9 @@ fn map_crate(&@env e, &@ast::crate c) {
 }
 
 fn resolve_imports(&env e) {
-    for each (@tup(ast::node_id, import_state) it in e.imports.items()) {
-        alt (it._1) {
+    for each (@rec(ast::node_id key, import_state val) it
+              in e.imports.items()) {
+        alt (it.val) {
             case (todo(?item, ?sc)) { resolve_import(e, item, sc); }
             case (resolved(_, _, _)) { }
         }
@@ -437,7 +439,7 @@ fn resolve_import(&env e, &@ast::view_item it, &scopes sc_in) {
             name = _name;
         }
     }
-    e.imports.insert(defid._1, resolving(it.span));
+    e.imports.insert(defid.node, resolving(it.span));
     auto n_idents = ivec::len(ids);
     auto end_id = ids.(n_idents - 1u);
     // Ignore the current scope if this import would shadow itself.
@@ -448,7 +450,7 @@ fn resolve_import(&env e, &@ast::view_item it, &scopes sc_in) {
                  lookup_in_scope(e, sc, it.span, end_id, ns_value),
                  lookup_in_scope(e, sc, it.span, end_id, ns_type),
                  lookup_in_scope(e, sc, it.span, end_id, ns_module));
-        remove_if_unresolved(e.imports, defid._1);
+        remove_if_unresolved(e.imports, defid.node);
     } else {
         auto dcur = alt(lookup_in_scope(e, sc, it.span, ids.(0), ns_module)) {
             case (some(?dcur)) {
@@ -456,7 +458,7 @@ fn resolve_import(&env e, &@ast::view_item it, &scopes sc_in) {
             }
             case (none) {
                 unresolved_err(e, sc, it.span, ids.(0), ns_name(ns_module));
-                remove_if_unresolved(e.imports, defid._1);
+                remove_if_unresolved(e.imports, defid.node);
                 ret () // FIXME (issue #521)
             }
         };
@@ -470,7 +472,7 @@ fn resolve_import(&env e, &@ast::view_item it, &scopes sc_in) {
                                        outside),
                          lookup_in_mod(e, dcur, it.span, end_id, ns_module,
                                        outside));
-                remove_if_unresolved(e.imports, defid._1);
+                remove_if_unresolved(e.imports, defid.node);
                 break;
             } else {
                 dcur = alt (lookup_in_mod(e, dcur, it.span, ids.(i),
@@ -481,7 +483,7 @@ fn resolve_import(&env e, &@ast::view_item it, &scopes sc_in) {
                     case (none) {
                         unresolved_err(e, sc, it.span, ids.(i),
                                        ns_name(ns_module));
-                        remove_if_unresolved(e.imports, defid._1);
+                        remove_if_unresolved(e.imports, defid.node);
                         ret () // FIXME (issue #521)
                     }
                 };
@@ -495,7 +497,7 @@ fn resolve_import(&env e, &@ast::view_item it, &scopes sc_in) {
         if is_none(val) && is_none(typ) && is_none(md) {
             unresolved_err(e, sc, sp, name, "import");
         } else {
-            e.imports.insert(defid._1, resolved(val, typ, md));
+            e.imports.insert(defid.node, resolved(val, typ, md));
         }
     }
     fn remove_if_unresolved(hashmap[ast::node_id, import_state] imports,
@@ -542,10 +544,10 @@ fn unresolved_err(&env e, &scopes sc, &span sp, &ident name, &str kind) {
         fail;
     }
     auto err_scope = find_fn_or_mod_scope(sc);
-    for (tup(str, scope) rs in e.reported) {
-        if str::eq(rs._0, name) && err_scope == rs._1 { ret; }
+    for (rec(str ident, scope sc) rs in e.reported) {
+        if str::eq(rs.ident, name) && err_scope == rs.sc { ret; }
     }
-    e.reported += ~[tup(name, err_scope)];
+    e.reported += ~[rec(ident=name, sc=err_scope)];
     e.sess.span_err(sp, mk_unresolved_msg(name, kind));
 }
 
@@ -899,25 +901,26 @@ fn lookup_in_mod_strict(&env e, &scopes sc, def m, &span sp, &ident name,
 fn lookup_in_mod(&env e, &def m, &span sp, &ident name, namespace ns,
                  dir dr) -> option::t[def] {
     auto defid = ast::def_id_of_def(m);
-    if (defid._0 != ast::local_crate) {
+    if (defid.crate != ast::local_crate) {
         // examining a module in an external crate
 
-        auto cached = e.ext_cache.find(tup(defid, name, ns));
+        auto cached = e.ext_cache.find(rec(did=defid, ident=name, ns=ns));
         if (!is_none(cached)) { ret cached; }
         auto path = ~[name];
-        if (defid._1 != -1) { path = e.ext_map.get(defid) + path; }
-        auto fnd = lookup_external(e, defid._0, path, ns);
+        if (defid.node != -1) { path = e.ext_map.get(defid) + path; }
+        auto fnd = lookup_external(e, defid.crate, path, ns);
         if (!is_none(fnd)) {
-            e.ext_cache.insert(tup(defid, name, ns), option::get(fnd));
+            e.ext_cache.insert(rec(did=defid, ident=name, ns=ns),
+                               option::get(fnd));
         }
         ret fnd;
     }
     alt (m) {
         case (ast::def_mod(?defid)) {
-            ret lookup_in_local_mod(e, defid._1, sp, name, ns, dr);
+            ret lookup_in_local_mod(e, defid.node, sp, name, ns, dr);
         }
         case (ast::def_native_mod(?defid)) {
-            ret lookup_in_local_native_mod(e, defid._1, sp, name, ns);
+            ret lookup_in_local_native_mod(e, defid.node, sp, name, ns);
         }
     }
 }
@@ -927,7 +930,7 @@ fn found_view_item(&env e, @ast::view_item vi, namespace ns) ->
     alt (vi.node) {
         case (ast::view_item_use(_, _, ?id)) {
             auto cnum = cstore::get_use_stmt_cnum(e.cstore, id);
-            ret some(ast::def_mod(tup(cnum, -1)));
+            ret some(ast::def_mod(rec(crate=cnum, node=-1)));
         }
         case (ast::view_item_import(_, _, ?id)) {
             ret lookup_import(e, local_def(id), ns);
@@ -940,7 +943,7 @@ fn found_view_item(&env e, @ast::view_item vi, namespace ns) ->
 }
 
 fn lookup_import(&env e, def_id defid, namespace ns) -> option::t[def] {
-    alt (e.imports.get(defid._1)) {
+    alt (e.imports.get(defid.node)) {
         case (todo(?item, ?sc)) {
             resolve_import(e, item, sc);
             ret lookup_import(e, defid, ns);
@@ -1002,9 +1005,9 @@ fn lookup_glob_in_mod(&env e, @indexed_mod info, &span sp, &ident id,
         fn lookup_in_mod_(&env e, &glob_imp_def def, &span sp,
                           &ident name, namespace ns,
                           dir dr) -> option::t[glob_imp_def] {
-            alt (lookup_in_mod(e, def._0, sp, name, ns, dr)) {
+            alt (lookup_in_mod(e, def.def, sp, name, ns, dr)) {
                 case (option::some(?d)) {
-                    option::some(tup(d, def._1))
+                    option::some(rec(def=d, item=def.item))
                 }
                 case (option::none) {
                     option::none
@@ -1016,12 +1019,12 @@ fn lookup_glob_in_mod(&env e, @indexed_mod info, &span sp, &ident id,
             ivec::filter_map(bind lookup_in_mod_(e, _, sp, id, ns, dr),
                              { info.glob_imports });
         if (ivec::len(matches) == 0u) {
-            ret none[def];
+            ret none;
         } else if (ivec::len(matches) == 1u) {
-            ret some[def](matches.(0)._0);
+            ret some(matches.(0).def);
         } else {
             for (glob_imp_def match in matches) {
-                auto sp = match._1.span;
+                auto sp = match.item.span;
                 e.sess.span_note(sp, #fmt("'%s' is imported here", id));
             }
             e.sess.span_fatal(sp,
@@ -1194,10 +1197,11 @@ fn check_for_collisions(&@env e, &ast::crate c) {
     // Module indices make checking those relatively simple -- just check each
     // name for multiple entities in the same namespace.
 
-    for each (@tup(ast::node_id, @indexed_mod) m in e.mod_map.items()) {
-        for each (@tup(ident, list[mod_index_entry]) name in
-                 m._1.index.items()) {
-            check_mod_name(*e, name._0, name._1);
+    for each (@rec(ast::node_id key, @indexed_mod val) m
+              in e.mod_map.items()) {
+        for each (@rec(ident key, list[mod_index_entry] val) name
+                  in m.val.index.items()) {
+            check_mod_name(*e, name.key, name.val);
         }
     }
     // Other scopes have to be checked the hard way.
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index ef62be865d3..4331e2c569a 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -313,10 +313,10 @@ fn type_of_arg(@local_ctxt cx, &span sp, &ty::arg arg) -> TypeRef {
 
 fn type_of_ty_param_count_and_ty(@local_ctxt lcx, &span sp,
                                  &ty::ty_param_count_and_ty tpt) -> TypeRef {
-    alt (ty::struct(lcx.ccx.tcx, tpt._1)) {
+    alt (ty::struct(lcx.ccx.tcx, tpt.ty)) {
         case (ty::ty_fn(?proto, ?inputs, ?output, _, _)) {
             auto llfnty =
-                type_of_fn(lcx.ccx, sp, proto, inputs, output, tpt._0);
+                type_of_fn(lcx.ccx, sp, proto, inputs, output, tpt.count);
             ret T_fn_pair(*lcx.ccx, llfnty);
         }
         case (_) {
@@ -324,7 +324,7 @@ fn type_of_ty_param_count_and_ty(@local_ctxt lcx, &span sp,
 
         }
     }
-    ret type_of(lcx.ccx, sp, tpt._1);
+    ret type_of(lcx.ccx, sp, tpt.ty);
 }
 
 fn type_of_or_i8(&@block_ctxt bcx, ty::t typ) -> TypeRef {
@@ -365,7 +365,7 @@ fn log_fn_time(&@crate_ctxt ccx, str name, &time::timeval start,
                &time::timeval end) {
     auto elapsed = 1000 * ((end.sec - start.sec) as int) +
         ((end.usec as int) - (start.usec as int)) / 1000;
-    *ccx.stats.fn_times += ~[tup(name, elapsed)];
+    *ccx.stats.fn_times += ~[rec(ident=name, time=elapsed)];
 }
 
 
@@ -911,7 +911,8 @@ fn field_of_tydesc(&@block_ctxt cx, &ty::t t, bool escapes, int field) ->
 // each of the ty params it uses (from the current frame) and a vector of the
 // indices of the ty params present in the type. This is used solely for
 // constructing derived tydescs.
-fn linearize_ty_params(&@block_ctxt cx, &ty::t t) -> tup(uint[], ValueRef[]) {
+fn linearize_ty_params(&@block_ctxt cx, &ty::t t)
+    -> rec(uint[] params, ValueRef[] descs) {
     let ValueRef[] param_vals = ~[];
     let uint[] param_defs = ~[];
     type rr = rec(@block_ctxt cx,
@@ -934,7 +935,7 @@ fn linearize_ty_params(&@block_ctxt cx, &ty::t t) -> tup(uint[], ValueRef[]) {
     auto x = @rec(cx=cx, mutable vals=param_vals, mutable defs=param_defs);
     auto f = bind linearizer(x, _);
     ty::walk_ty(cx.fcx.lcx.ccx.tcx, f, t);
-    ret tup(x.defs, x.vals);
+    ret rec(params=x.defs, descs=x.vals);
 }
 
 fn trans_stack_local_derived_tydesc(&@block_ctxt cx, ValueRef llsz,
@@ -971,9 +972,9 @@ fn get_derived_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
     auto bcx = new_raw_block_ctxt(cx.fcx, cx.fcx.llderivedtydescs);
     let uint n_params = ty::count_ty_params(bcx.fcx.lcx.ccx.tcx, t);
     auto tys = linearize_ty_params(bcx, t);
-    assert (n_params == std::ivec::len[uint](tys._0));
-    assert (n_params == std::ivec::len[ValueRef](tys._1));
-    auto root_ti = get_static_tydesc(bcx, t, tys._0);
+    assert (n_params == std::ivec::len[uint](tys.params));
+    assert (n_params == std::ivec::len[ValueRef](tys.descs));
+    auto root_ti = get_static_tydesc(bcx, t, tys.params);
     static_ti = some[@tydesc_info](root_ti);
     lazily_emit_all_tydesc_glue(cx, static_ti);
     auto root = root_ti.tydesc;
@@ -992,7 +993,7 @@ fn get_derived_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
         auto tdp = bcx.build.GEP(tydescs, ~[C_int(0), C_int(i)]);
         bcx.build.Store(root, tdp);
         i += 1;
-        for (ValueRef td in tys._1) {
+        for (ValueRef td in tys.descs) {
             auto tdp = bcx.build.GEP(tydescs, ~[C_int(0), C_int(i)]);
             bcx.build.Store(td, tdp);
             i += 1;
@@ -1011,7 +1012,7 @@ fn get_derived_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
             alloca(bcx,
                    T_array(T_ptr(bcx.fcx.lcx.ccx.tydesc_type), n_params));
         auto i = 0;
-        for (ValueRef td in tys._1) {
+        for (ValueRef td in tys.descs) {
             auto tdp = bcx.build.GEP(llparamtydescs, ~[C_int(0), C_int(i)]);
             bcx.build.Store(td, tdp);
             i += 1;
@@ -1211,10 +1212,11 @@ fn make_generic_glue(&@local_ctxt cx, &span sp, &ty::t t, ValueRef llfn,
 }
 
 fn emit_tydescs(&@crate_ctxt ccx) {
-    for each (@tup(ty::t, @tydesc_info) pair in ccx.tydescs.items()) {
+    for each (@rec(ty::t key, @tydesc_info val) pair
+              in ccx.tydescs.items()) {
         auto glue_fn_ty = T_ptr(T_glue_fn(*ccx));
         auto cmp_fn_ty = T_ptr(T_cmp_glue_fn(*ccx));
-        auto ti = pair._1;
+        auto ti = pair.val;
         auto copy_glue =
             alt ({ ti.copy_glue }) {
                 case (none) {
@@ -1478,8 +1480,8 @@ fn trans_res_drop(@block_ctxt cx, ValueRef rs, &ast::def_id did,
     auto val = GEP_tup_like(cx, tup_ty, rs, ~[0, 1]);
     cx = val.bcx;
     // Find and call the actual destructor.
-    auto dtor_pair = if (did._0 == ast::local_crate) {
-        alt (ccx.fn_pairs.find(did._1)) {
+    auto dtor_pair = if (did.crate == ast::local_crate) {
+        alt (ccx.fn_pairs.find(did.node)) {
             case (some(?x)) { x }
             case (_) { ccx.tcx.sess.bug("internal error in trans_res_drop") }
         }
@@ -1620,14 +1622,12 @@ fn make_cmp_glue(&@block_ctxt cx, ValueRef lhs0, ValueRef rhs0, &ty::t t,
             auto bcx;
             if (ty::sequence_is_interior(cx.fcx.lcx.ccx.tcx, t)) {
                 auto st = ty::sequence_element_type(cx.fcx.lcx.ccx.tcx, t);
-                auto lad =
-                    ivec::get_len_and_data(scx, lhs, st);
-                bcx = lad._2;
-                lhs_fill = lad._0;
-                lad =
-                    ivec::get_len_and_data(bcx, rhs, st);
-                bcx = lad._2;
-                rhs_fill = lad._0;
+                auto lad = ivec::get_len_and_data(scx, lhs, st);
+                bcx = lad.bcx;
+                lhs_fill = lad.len;
+                lad = ivec::get_len_and_data(bcx, rhs, st);
+                bcx = lad.bcx;
+                rhs_fill = lad.len;
             } else {
                 lhs_fill = vec_fill(scx, lhs);
                 rhs_fill = vec_fill(scx, rhs);
@@ -1914,13 +1914,13 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv,
         auto unit_sz = rs.val;
         bcx = rs.bcx;
         auto a_len_and_data = ivec::get_len_and_data(bcx, av, unit_ty);
-        auto a_len = a_len_and_data._0;
-        auto a_elem = a_len_and_data._1;
-        bcx = a_len_and_data._2;
+        auto a_len = a_len_and_data.len;
+        auto a_elem = a_len_and_data.data;
+        bcx = a_len_and_data.bcx;
         auto b_len_and_data = ivec::get_len_and_data(bcx, bv, unit_ty);
-        auto b_len = b_len_and_data._0;
-        auto b_elem = b_len_and_data._1;
-        bcx = b_len_and_data._2;
+        auto b_len = b_len_and_data.len;
+        auto b_elem = b_len_and_data.data;
+        bcx = b_len_and_data.bcx;
         // Calculate the last pointer address we want to handle.
         // TODO: Optimize this when the size of the unit type is statically
         // known to not use pointer casts, which tend to confuse LLVM.
@@ -2190,9 +2190,9 @@ fn iter_sequence(@block_ctxt cx, ValueRef v, &ty::t t, &val_and_ty_fn f) ->
             bcx = cx;
         } else {
             auto len_and_data_rslt = ivec::get_len_and_data(cx, v, elt_ty);
-            len = len_and_data_rslt._0;
-            p0 = len_and_data_rslt._1;
-            bcx = len_and_data_rslt._2;
+            len = len_and_data_rslt.len;
+            p0 = len_and_data_rslt.data;
+            bcx = len_and_data_rslt.bcx;
         }
 
         auto llunit_ty = type_of_or_i8(cx, elt_ty);
@@ -2881,7 +2881,7 @@ mod ivec {
     // Returns the length of an interior vector and a pointer to its first
     // element, in that order.
     fn get_len_and_data(&@block_ctxt bcx, ValueRef orig_v, ty::t unit_ty)
-            -> tup(ValueRef, ValueRef, @block_ctxt) {
+            -> rec(ValueRef len, ValueRef data, @block_ctxt bcx) {
         // If this interior vector has dynamic size, we can't assume anything
         // about the LLVM type of the value passed in, so we cast it to an
         // opaque vector type.
@@ -2953,7 +2953,7 @@ mod ivec {
                               ~[stack_elem, zero_elem, heap_elem],
                               ~[bcx.llbb, zero_len_cx.llbb,
                                 nonzero_len_cx.llbb]);
-        ret tup(len, elem, next_cx);
+        ret rec(len=len, data=elem, bcx=next_cx);
     }
 
     // Returns a tuple consisting of a pointer to the newly-reserved space and
@@ -3131,9 +3131,9 @@ mod ivec {
         lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, none);
         lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, none);
         auto rhs_len_and_data = get_len_and_data(bcx, rhs, unit_ty);
-        auto rhs_len = rhs_len_and_data._0;
-        auto rhs_data = rhs_len_and_data._1;
-        bcx = rhs_len_and_data._2;
+        auto rhs_len = rhs_len_and_data.len;
+        auto rhs_data = rhs_len_and_data.data;
+        bcx = rhs_len_and_data.bcx;
         rs = reserve_space(bcx, llunitty, lhs, rhs_len);
         auto lhs_data = rs.val;
         bcx = rs.bcx;
@@ -3244,13 +3244,13 @@ mod ivec {
         auto llunitty = type_of_or_i8(bcx, unit_ty);
         auto llheappartty = T_ivec_heap_part(llunitty);
         auto lhs_len_and_data = get_len_and_data(bcx, lhs, unit_ty);
-        auto lhs_len = lhs_len_and_data._0;
-        auto lhs_data = lhs_len_and_data._1;
-        bcx = lhs_len_and_data._2;
+        auto lhs_len = lhs_len_and_data.len;
+        auto lhs_data = lhs_len_and_data.data;
+        bcx = lhs_len_and_data.bcx;
         auto rhs_len_and_data = get_len_and_data(bcx, rhs, unit_ty);
-        auto rhs_len = rhs_len_and_data._0;
-        auto rhs_data = rhs_len_and_data._1;
-        bcx = rhs_len_and_data._2;
+        auto rhs_len = rhs_len_and_data.len;
+        auto rhs_data = rhs_len_and_data.data;
+        bcx = rhs_len_and_data.bcx;
         auto lllen = bcx.build.Add(lhs_len, rhs_len);
         // We have three cases to handle here:
         // (1) Length is zero ([] + []).
@@ -4053,10 +4053,10 @@ fn trans_external_path(&@block_ctxt cx, &ast::def_id did,
 fn lval_generic_fn(&@block_ctxt cx, &ty::ty_param_count_and_ty tpt,
                    &ast::def_id fn_id, ast::node_id id) -> lval_result {
     auto lv;
-    if (fn_id._0 == ast::local_crate) {
+    if (fn_id.crate == ast::local_crate) {
         // Internal reference.
-        assert (cx.fcx.lcx.ccx.fn_pairs.contains_key(fn_id._1));
-        lv = lval_val(cx, cx.fcx.lcx.ccx.fn_pairs.get(fn_id._1));
+        assert (cx.fcx.lcx.ccx.fn_pairs.contains_key(fn_id.node));
+        lv = lval_val(cx, cx.fcx.lcx.ccx.fn_pairs.get(fn_id.node));
     } else {
         // External reference.
         lv = lval_val(cx, trans_external_path(cx, fn_id, tpt));
@@ -4075,7 +4075,7 @@ fn lval_generic_fn(&@block_ctxt cx, &ty::ty_param_count_and_ty tpt,
             bcx = td.bcx;
             tydescs += ~[td.val];
         }
-        auto gen = rec(item_type=tpt._1, static_tis=tis, tydescs=tydescs);
+        auto gen = rec(item_type=tpt.ty, static_tis=tis, tydescs=tydescs);
         lv = rec(res=rslt(bcx, lv.res.val), generic=some[generic_info](gen)
                  with lv);
     }
@@ -4084,11 +4084,10 @@ fn lval_generic_fn(&@block_ctxt cx, &ty::ty_param_count_and_ty tpt,
 
 fn lookup_discriminant(&@local_ctxt lcx, &ast::def_id tid, &ast::def_id vid)
    -> ValueRef {
-    alt (lcx.ccx.discrims.find(vid._1)) {
+    alt (lcx.ccx.discrims.find(vid.node)) {
         case (none) {
             // It's an external discriminant that we haven't seen yet.
-
-            assert (vid._0 != ast::local_crate);
+            assert (vid.crate != ast::local_crate);
             auto sym = csearch::get_symbol(lcx.ccx.sess.get_cstore(), vid);
             auto gvar =
                 llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(sym));
@@ -4096,7 +4095,7 @@ fn lookup_discriminant(&@local_ctxt lcx, &ast::def_id tid, &ast::def_id vid)
                                  lib::llvm::LLVMExternalLinkage as
                                      llvm::Linkage);
             llvm::LLVMSetGlobalConstant(gvar, True);
-            lcx.ccx.discrims.insert(vid._1, gvar);
+            lcx.ccx.discrims.insert(vid.node, gvar);
             ret gvar;
         }
         case (some(?llval)) { ret llval; }
@@ -4107,35 +4106,35 @@ fn trans_path(&@block_ctxt cx, &ast::path p, ast::node_id id) -> lval_result {
     auto ccx = cx.fcx.lcx.ccx;
     alt (cx.fcx.lcx.ccx.tcx.def_map.find(id)) {
         case (some(ast::def_arg(?did))) {
-            alt (cx.fcx.llargs.find(did._1)) {
+            alt (cx.fcx.llargs.find(did.node)) {
                 case (none) {
-                    assert (cx.fcx.llupvars.contains_key(did._1));
-                    ret lval_mem(cx, cx.fcx.llupvars.get(did._1));
+                    assert (cx.fcx.llupvars.contains_key(did.node));
+                    ret lval_mem(cx, cx.fcx.llupvars.get(did.node));
                 }
                 case (some(?llval)) { ret lval_mem(cx, llval); }
             }
         }
         case (some(ast::def_local(?did))) {
-            alt (cx.fcx.lllocals.find(did._1)) {
+            alt (cx.fcx.lllocals.find(did.node)) {
                 case (none) {
-                    assert (cx.fcx.llupvars.contains_key(did._1));
-                    ret lval_mem(cx, cx.fcx.llupvars.get(did._1));
+                    assert (cx.fcx.llupvars.contains_key(did.node));
+                    ret lval_mem(cx, cx.fcx.llupvars.get(did.node));
                 }
                 case (some(?llval)) { ret lval_mem(cx, llval); }
             }
         }
         case (some(ast::def_binding(?did))) {
-            alt (cx.fcx.lllocals.find(did._1)) {
+            alt (cx.fcx.lllocals.find(did.node)) {
                 case (none) {
-                    assert (cx.fcx.llupvars.contains_key(did._1));
-                    ret lval_mem(cx, cx.fcx.llupvars.get(did._1));
+                    assert (cx.fcx.llupvars.contains_key(did.node));
+                    ret lval_mem(cx, cx.fcx.llupvars.get(did.node));
                 }
                 case (some(?llval)) { ret lval_mem(cx, llval); }
             }
         }
         case (some(ast::def_obj_field(?did))) {
-            assert (cx.fcx.llobjfields.contains_key(did._1));
-            ret lval_mem(cx, cx.fcx.llobjfields.get(did._1));
+            assert (cx.fcx.llobjfields.contains_key(did.node));
+            ret lval_mem(cx, cx.fcx.llobjfields.get(did.node));
         }
         case (some(ast::def_fn(?did, _))) {
             auto tyt = ty::lookup_item_type(ccx.tcx, did);
@@ -4143,7 +4142,7 @@ fn trans_path(&@block_ctxt cx, &ast::path p, ast::node_id id) -> lval_result {
         }
         case (some(ast::def_variant(?tid, ?vid))) {
             auto v_tyt = ty::lookup_item_type(ccx.tcx, vid);
-            alt (ty::struct(ccx.tcx, v_tyt._1)) {
+            alt (ty::struct(ccx.tcx, v_tyt.ty)) {
                 case (ty::ty_fn(_, _, _, _, _)) {
                     // N-ary variant.
 
@@ -4172,14 +4171,14 @@ fn trans_path(&@block_ctxt cx, &ast::path p, ast::node_id id) -> lval_result {
             }
         }
         case (some(ast::def_const(?did))) {
-          if (did._0 == ast::local_crate) {
-              assert (ccx.consts.contains_key(did._1));
-              ret lval_mem(cx, ccx.consts.get(did._1));
+          if (did.crate == ast::local_crate) {
+              assert (ccx.consts.contains_key(did.node));
+              ret lval_mem(cx, ccx.consts.get(did.node));
           } else {
               auto tp = ty::node_id_to_monotype(ccx.tcx, id);
               ret lval_val(cx, load_if_immediate
                            (cx, trans_external_path
-                            (cx, did, tup(0u, tp)), tp));
+                            (cx, did, rec(count=0u, ty=tp)), tp));
           }
         }
         case (some(ast::def_native_fn(?did))) {
@@ -4274,12 +4273,12 @@ fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, &@ast::expr idx,
     auto interior_len_and_data;
     if (is_interior) {
         auto rslt = ivec::get_len_and_data(bcx, v, unit_ty);
-        interior_len_and_data = some(tup(rslt._0, rslt._1));
-        bcx = rslt._2;
+        interior_len_and_data = some(rec(len=rslt.len, data=rslt.data));
+        bcx = rslt.bcx;
     } else { interior_len_and_data = none; }
     auto lim;
     alt (interior_len_and_data) {
-        case (some(?lad)) { lim = lad._0; }
+        case (some(?lad)) { lim = lad.len; }
         case (none) {
             lim = bcx.build.GEP(v, ~[C_int(0), C_int(abi::vec_elt_fill)]);
             lim = bcx.build.Load(lim);
@@ -4294,7 +4293,7 @@ fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, &@ast::expr idx,
     trans_fail(fail_cx, some[span](sp), "bounds check");
     auto body;
     alt (interior_len_and_data) {
-        case (some(?lad)) { body = lad._1; }
+        case (some(?lad)) { body = lad.data; }
         case (none) {
             body =
                 next_cx.build.GEP(v,
@@ -4907,7 +4906,7 @@ fn trans_arg_expr(&@block_ctxt cx, &ty::arg arg, TypeRef lldestty0,
 fn trans_args(&@block_ctxt cx, ValueRef llenv, &option::t[ValueRef] llobj,
               &option::t[generic_info] gen, &option::t[ValueRef] lliterbody,
               &(@ast::expr)[] es, &ty::t fn_ty)
-        -> tup(@block_ctxt, ValueRef[], ValueRef) {
+        -> rec(@block_ctxt bcx, ValueRef[] args, ValueRef retslot) {
     let ty::arg[] args = ty::ty_fn_args(cx.fcx.lcx.ccx.tcx, fn_ty);
     let ValueRef[] llargs = ~[];
     let ValueRef[] lltydescs = ~[];
@@ -4919,7 +4918,7 @@ fn trans_args(&@block_ctxt cx, ValueRef llenv, &option::t[ValueRef] llobj,
     if (bcx.build.is_terminated()) {
         // This means an earlier arg was divergent.
         // So this arg can't be evaluated.
-        ret tup(bcx, ~[], C_nil());
+        ret rec(bcx=bcx, args=~[], retslot=C_nil());
     }
 
     auto retty = ty::ty_fn_ret(cx.fcx.lcx.ccx.tcx, fn_ty);
@@ -4994,7 +4993,7 @@ fn trans_args(&@block_ctxt cx, ValueRef llenv, &option::t[ValueRef] llobj,
         llargs += ~[r.val];
         i += 1u;
     }
-    ret tup(bcx, llargs, llretslot);
+    ret rec(bcx=bcx, args=llargs, retslot=llretslot);
 }
 
 fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
@@ -5045,9 +5044,9 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
     auto args_res =
         trans_args(bcx, llenv, f_res.llobj, f_res.generic,
                    lliterbody, args, fn_ty);
-    bcx = args_res._0;
-    auto llargs = args_res._1;
-    auto llretslot = args_res._2;
+    bcx = args_res.bcx;
+    auto llargs = args_res.args;
+    auto llretslot = args_res.retslot;
     /*
     log "calling: " + val_str(cx.fcx.lcx.ccx.tn, faddr);
 
@@ -6416,11 +6415,12 @@ fn new_local_ctxt(&@crate_ctxt ccx) -> @local_ctxt {
 // Creates the standard quartet of basic blocks: static allocas, copy args,
 // derived tydescs, and dynamic allocas.
 fn mk_standard_basic_blocks(ValueRef llfn) ->
-   tup(BasicBlockRef, BasicBlockRef, BasicBlockRef, BasicBlockRef) {
-    ret tup(llvm::LLVMAppendBasicBlock(llfn, str::buf("static_allocas")),
-            llvm::LLVMAppendBasicBlock(llfn, str::buf("copy_args")),
-            llvm::LLVMAppendBasicBlock(llfn, str::buf("derived_tydescs")),
-            llvm::LLVMAppendBasicBlock(llfn, str::buf("dynamic_allocas")));
+    rec(BasicBlockRef sa, BasicBlockRef ca,
+        BasicBlockRef dt, BasicBlockRef da) {
+    ret rec(sa=llvm::LLVMAppendBasicBlock(llfn, str::buf("static_allocas")),
+            ca=llvm::LLVMAppendBasicBlock(llfn, str::buf("copy_args")),
+            dt=llvm::LLVMAppendBasicBlock(llfn, str::buf("derived_tydescs")),
+            da=llvm::LLVMAppendBasicBlock(llfn, str::buf("dynamic_allocas")));
 }
 
 
@@ -6446,11 +6446,11 @@ fn new_fn_ctxt(@local_ctxt cx, &span sp, ValueRef llfndecl) -> @fn_ctxt {
              lltaskptr=lltaskptr,
              llenv=llenv,
              llretptr=llretptr,
-             mutable llstaticallocas=llbbs._0,
-             mutable llcopyargs=llbbs._1,
-             mutable llderivedtydescs_first=llbbs._2,
-             mutable llderivedtydescs=llbbs._2,
-             mutable lldynamicallocas=llbbs._3,
+             mutable llstaticallocas=llbbs.sa,
+             mutable llcopyargs=llbbs.ca,
+             mutable llderivedtydescs_first=llbbs.dt,
+             mutable llderivedtydescs=llbbs.dt,
+             mutable lldynamicallocas=llbbs.da,
              mutable llself=none[val_self_pair],
              mutable lliterbody=none[ValueRef],
              llargs=llargs,
@@ -7788,8 +7788,8 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
     fn trans_simple_native_abi(&@block_ctxt bcx, str name,
                                &mutable ValueRef[] call_args,
                                ty::t fn_type, uint first_arg_n,
-                               bool uses_retptr, uint cc) ->
-       tup(ValueRef, ValueRef) {
+                               bool uses_retptr, uint cc)
+        -> rec(ValueRef val, ValueRef rptr) {
         let TypeRef[] call_arg_tys = ~[];
         for (ValueRef arg in call_args) { call_arg_tys += ~[val_ty(arg)]; }
 
@@ -7812,13 +7812,13 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
             bcx.build.CallWithConv(llnativefn, call_args, cc)
         };
         auto rptr = bcx.fcx.llretptr;
-        ret tup(r, rptr);
+        ret rec(val=r, rptr=rptr);
     }
 
     auto args = ty::ty_fn_args(ccx.tcx, fn_type);
     // Build up the list of arguments.
 
-    let (tup(ValueRef, ty::t))[] drop_args = ~[];
+    let (rec(ValueRef val, ty::t ty))[] drop_args = ~[];
     auto i = arg_n;
     for (ty::arg arg in args) {
         auto llarg = llvm::LLVMGetParam(fcx.llfn, i);
@@ -7829,7 +7829,9 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
         } else {
             call_args += ~[llarg];
         }
-        if (arg.mode == ty::mo_val) { drop_args += ~[tup(llarg, arg.ty)]; }
+        if (arg.mode == ty::mo_val) {
+            drop_args += ~[rec(val=llarg, ty=arg.ty)];
+        }
         i += 1u;
     }
     auto r;
@@ -7840,8 +7842,8 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
                 trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n,
                                         uses_retptr,
                                         lib::llvm::LLVMCCallConv);
-            r = result._0;
-            rptr = result._1;
+            r = result.val;
+            rptr = result.rptr;
         }
         case (ast::native_abi_rust_intrinsic) {
             auto external_name = "rust_intrinsic_" + name;
@@ -7849,16 +7851,16 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
                 trans_simple_native_abi(bcx, external_name, call_args,
                                         fn_type, arg_n, uses_retptr,
                                         lib::llvm::LLVMCCallConv);
-            r = result._0;
-            rptr = result._1;
+            r = result.val;
+            rptr = result.rptr;
         }
         case (ast::native_abi_x86stdcall) {
             auto result =
                 trans_simple_native_abi(bcx, name, call_args, fn_type, arg_n,
                                         uses_retptr,
                                         lib::llvm::LLVMX86StdcallCallConv);
-            r = result._0;
-            rptr = result._1;
+            r = result.val;
+            rptr = result.rptr;
         }
         case (_) {
             r =
@@ -7874,8 +7876,8 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, &span sp, &str[] path, str name,
 
     if (!rty_is_nil && !uses_retptr) { bcx.build.Store(r, rptr); }
 
-    for (tup(ValueRef, ty::t) d in drop_args) {
-        bcx = drop_ty(bcx, d._0, d._1).bcx;
+    for (rec(ValueRef val, ty::t ty) d in drop_args) {
+        bcx = drop_ty(bcx, d.val, d.ty).bcx;
     }
     bcx.build.RetVoid();
     finish_fn(fcx, lltop);
@@ -8130,8 +8132,8 @@ fn create_module_map(&@crate_ctxt ccx) -> ValueRef {
                          lib::llvm::LLVMInternalLinkage as
                          llvm::Linkage);
     let ValueRef[] elts = ~[];
-    for each (@tup(str, ValueRef) item in ccx.module_data.items()) {
-        auto elt = C_struct(~[p2i(C_cstr(ccx, item._0)), p2i(item._1)]);
+    for each (@rec(str key, ValueRef val) item in ccx.module_data.items()) {
+        auto elt = C_struct(~[p2i(C_cstr(ccx, item.key)), p2i(item.val)]);
         elts += ~[elt];
     }
     auto term = C_struct(~[C_int(0), C_int(0)]);
@@ -8271,8 +8273,8 @@ fn trans_crate(&session::session sess, &@ast::crate crate, &ty::ctxt tcx,
         log_err #fmt("n_null_glues: %u", ccx.stats.n_null_glues);
         log_err #fmt("n_real_glues: %u", ccx.stats.n_real_glues);
 
-        for (tup(str,int) timing in *ccx.stats.fn_times) {
-            log_err #fmt("time: %s took %d ms", timing._0, timing._1);
+        for (rec(str ident, int time) timing in *ccx.stats.fn_times) {
+            log_err #fmt("time: %s took %d ms", timing.ident, timing.time);
         }
     }
     ret llmod;
diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs
index fa53c868536..f88ec69c09b 100644
--- a/src/comp/middle/trans_alt.rs
+++ b/src/comp/middle/trans_alt.rs
@@ -23,7 +23,7 @@ import trans_common::*;
 // An option identifying a branch (either a literal or a tag variant)
 tag opt {
     lit(@ast::lit);
-    var(uint /* variant id */, tup(def_id, def_id) /* variant def ids */);
+    var(uint /* variant id */, rec(def_id tg, def_id var) /* variant dids */);
 }
 fn opt_eq(&opt a, &opt b) -> bool {
     alt (a) {
@@ -44,16 +44,16 @@ fn trans_opt(&@block_ctxt bcx, &opt o) -> result {
 
 fn variant_opt(&@crate_ctxt ccx, ast::node_id pat_id) -> opt {
     auto vdef = ast::variant_def_ids(ccx.tcx.def_map.get(pat_id));
-    auto variants = ty::tag_variants(ccx.tcx, vdef._0);
+    auto variants = ty::tag_variants(ccx.tcx, vdef.tg);
     auto i = 0u;
     for (ty::variant_info v in variants) {
-        if (vdef._1 == v.id) { ret var(i, vdef); }
+        if (vdef.var == v.id) { ret var(i, vdef); }
         i += 1u;
     }
     fail;
 }
 
-type bind_map = tup(ast::ident, ValueRef)[];
+type bind_map = rec(ast::ident ident, ValueRef val)[];
 type match_branch = @rec((@ast::pat)[] pats,
                          BasicBlockRef body,
                          mutable bind_map bound);
@@ -72,7 +72,7 @@ fn matches_always(&@ast::pat p) -> bool {
 fn bind_for_pat(&@ast::pat p, &match_branch br, ValueRef val) {
     alt p.node {
         ast::pat_bind(?name) {
-            br.bound += ~[tup(name, val)];
+            br.bound += ~[rec(ident=name, val=val)];
         }
         _ {}
     }
@@ -184,15 +184,15 @@ fn get_options(&@crate_ctxt ccx, &match m, uint col) -> opt[] {
 }
 
 fn extract_variant_args(@block_ctxt bcx, ast::node_id pat_id,
-                        &tup(def_id, def_id) vdefs, ValueRef val)
-    -> tup(ValueRef[], @block_ctxt) {
+                        &rec(def_id tg, def_id var) vdefs, ValueRef val)
+    -> rec(ValueRef[] vals, @block_ctxt bcx) {
     auto ccx = bcx.fcx.lcx.ccx;
     auto ty_param_substs = ty::node_id_to_type_params(ccx.tcx, pat_id);
     auto blobptr = val;
-    auto variants = ty::tag_variants(ccx.tcx, vdefs._0);
+    auto variants = ty::tag_variants(ccx.tcx, vdefs.tg);
     auto args = ~[];
     auto size = ivec::len(ty::tag_variant_with_id
-                          (ccx.tcx, vdefs._0, vdefs._1).args);
+                          (ccx.tcx, vdefs.tg, vdefs.var).args);
     if (size > 0u && ivec::len(variants) != 1u) {
         auto tagptr = bcx.build.PointerCast
             (val, trans_common::T_opaque_tag_ptr(ccx.tn));
@@ -200,13 +200,13 @@ fn extract_variant_args(@block_ctxt bcx, ast::node_id pat_id,
     }
     auto i = 0u;
     while (i < size) {
-        auto r = trans::GEP_tag(bcx, blobptr, vdefs._0, vdefs._1,
+        auto r = trans::GEP_tag(bcx, blobptr, vdefs.tg, vdefs.var,
                                 ty_param_substs, i as int);
         bcx = r.bcx;
         args += ~[r.val];
         i += 1u;
     }
-    ret tup(args, bcx);
+    ret rec(vals=args, bcx=bcx);
 }
 
 fn collect_record_fields(&match m, uint col) -> ast::ident[] {
@@ -305,7 +305,7 @@ fn compile_submatch(@block_ctxt bcx, &match m, ValueRef[] vals, &mk_fail f,
     if (ivec::len(opts) > 0u) {
         alt (opts.(0)) {
             var(_, ?vdef) {
-                if (ivec::len(ty::tag_variants(ccx.tcx, vdef._0)) == 1u) {
+                if (ivec::len(ty::tag_variants(ccx.tcx, vdef.tg)) == 1u) {
                     kind = single;
                 } else {
                     auto tagptr = bcx.build.PointerCast
@@ -359,9 +359,9 @@ fn compile_submatch(@block_ctxt bcx, &match m, ValueRef[] vals, &mk_fail f,
         alt opt {
              var(_, ?vdef) {
                  auto args = extract_variant_args(opt_cx, pat_id, vdef, val);
-                 size = ivec::len(args._0);
-                 unpacked = args._0;
-                 opt_cx = args._1;
+                 size = ivec::len(args.vals);
+                 unpacked = args.vals;
+                 opt_cx = args.bcx;
              }
              lit(_) { }
         }
@@ -380,21 +380,23 @@ fn compile_submatch(@block_ctxt bcx, &match m, ValueRef[] vals, &mk_fail f,
 // Returns false for unreachable blocks
 fn make_phi_bindings(&@block_ctxt bcx, &exit_node[] map,
                      &ast::pat_id_map ids) -> bool {
-    fn assoc(str key, &tup(str, ValueRef)[] list) -> option::t[ValueRef] {
-        for (tup(str, ValueRef) elt in list) {
-            if (str::eq(elt._0, key)) { ret some(elt._1); }
+    fn assoc(str key, &bind_map list)
+        -> option::t[ValueRef] {
+        for (rec(ast::ident ident, ValueRef val) elt in list) {
+            if (str::eq(elt.ident, key)) { ret some(elt.val); }
         }
         ret none;
     }
 
     auto our_block = bcx.llbb as uint;
     auto success = true;
-    for each (@tup(ast::ident, ast::node_id) item in ids.items()) {
+    for each (@rec(ast::ident key, ast::node_id val) item
+              in ids.items()) {
         auto llbbs = ~[];
         auto vals = ~[];
         for (exit_node ex in map) {
             if (ex.to as uint == our_block) {
-                alt (assoc(item._0, ex.bound)) {
+                alt (assoc(item.key, ex.bound)) {
                     some(?val) {
                         llbbs += ~[ex.from];
                         vals += ~[val];
@@ -405,7 +407,7 @@ fn make_phi_bindings(&@block_ctxt bcx, &exit_node[] map,
         }
         if (ivec::len(vals) > 0u) {
             auto phi = bcx.build.Phi(val_ty(vals.(0)), vals, llbbs);
-            bcx.fcx.lllocals.insert(item._1, phi);
+            bcx.fcx.lllocals.insert(item.val, phi);
         } else { success = false; }
     }
     ret success;
diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs
index d5b926f482d..5df95fd0a10 100644
--- a/src/comp/middle/trans_common.rs
+++ b/src/comp/middle/trans_common.rs
@@ -101,7 +101,7 @@ type stats =
         mutable uint n_glues_created,
         mutable uint n_null_glues,
         mutable uint n_real_glues,
-        @mutable (tup(str,int)[]) fn_times);
+        @mutable (rec(str ident, int time)[]) fn_times);
 
 // Crate context.  Every crate we compile has one of these.
 type crate_ctxt =
diff --git a/src/comp/middle/trans_dps.rs b/src/comp/middle/trans_dps.rs
index 9c1f5087dd7..331b7d9f148 100644
--- a/src/comp/middle/trans_dps.rs
+++ b/src/comp/middle/trans_dps.rs
@@ -234,7 +234,7 @@ fn malloc(&@block_ctxt bcx, ValueRef lldest, heap heap,
 // If the supplied destination is an alias, spills to a temporary. Returns the
 // new destination.
 fn spill_alias(&@block_ctxt cx, &dest dest, ty::t t)
-        -> tup(@block_ctxt, dest) {
+        -> rec(@block_ctxt bcx, dest dest) {
     auto bcx = cx;
     alt (dest) {
       dst_alias(?box) {
@@ -243,22 +243,22 @@ fn spill_alias(&@block_ctxt cx, &dest dest, ty::t t)
         auto r = trans::alloc_ty(cx, t);
         bcx = r.bcx; auto llptr = r.val;
         *box = some(llptr);
-        ret tup(bcx, dst_move(llptr));
+        ret rec(bcx=bcx, dest=dst_move(llptr));
       }
-      _ { ret tup(bcx, dest); }
+      _ { ret rec(bcx=bcx, dest=dest); }
     }
 }
 
-fn mk_temp(&@block_ctxt cx, ty::t t) -> tup(@block_ctxt, dest) {
+fn mk_temp(&@block_ctxt cx, ty::t t) -> rec(@block_ctxt bcx, dest dest) {
     auto bcx = cx;
-    if ty::type_is_nil(bcx_tcx(bcx), t) { ret tup(bcx, dst_nil); }
+    if ty::type_is_nil(bcx_tcx(bcx), t) { ret rec(bcx=bcx, dest=dst_nil); }
     if trans::type_is_immediate(bcx_ccx(bcx), t) {
-        ret tup(bcx, dst_imm(@mutable none));
+        ret rec(bcx=bcx, dest=dst_imm(@mutable none));
     }
 
     auto r = trans::alloc_ty(cx, t);
     bcx = r.bcx; auto llptr = r.val;
-    ret tup(bcx, dst_copy(llptr));
+    ret rec(bcx=bcx, dest=dst_copy(llptr));
 }
 
 
@@ -269,7 +269,7 @@ fn trans_lit(&@block_ctxt cx, &dest dest, &ast::lit lit) -> @block_ctxt {
     alt (lit.node) {
       ast::lit_str(?s, ast::sk_unique) {
         auto r = trans_lit_str_common(bcx_ccx(bcx), s, dest_is_alias(dest));
-        auto llstackpart = r._0; auto llheappartopt = r._1;
+        auto llstackpart = r.stack; auto llheappartopt = r.heap;
         bcx = store_ptr(bcx, dest, llstackpart);
         alt (llheappartopt) {
           none { /* no-op */ }
@@ -336,27 +336,27 @@ fn trans_log(&@block_ctxt cx, &span sp, int level, &@ast::expr expr)
 
     tag upcall_style { us_imm; us_imm_i32_zext; us_alias; us_alias_istr; }
     fn get_upcall(&@crate_ctxt ccx, &span sp, ty::t t)
-            -> tup(ValueRef, upcall_style) {
+            -> rec(ValueRef val, upcall_style st) {
         alt (ty::struct(ccx_tcx(ccx), t)) {
           ty::ty_machine(ast::ty_f32) {
-            ret tup(ccx.upcalls.log_float, us_imm);
+            ret rec(val=ccx.upcalls.log_float, st=us_imm);
           }
           ty::ty_machine(ast::ty_f64) | ty::ty_float {
             // TODO: We have to spill due to legacy calling conventions that
             // should probably be modernized.
-            ret tup(ccx.upcalls.log_double, us_alias);
+            ret rec(val=ccx.upcalls.log_double, st=us_alias);
           }
           ty::ty_bool | ty::ty_machine(ast::ty_i8) |
                 ty::ty_machine(ast::ty_i16) | ty::ty_machine(ast::ty_u8) |
                 ty::ty_machine(ast::ty_u16) {
-            ret tup(ccx.upcalls.log_int, us_imm_i32_zext);
+            ret rec(val=ccx.upcalls.log_int, st=us_imm_i32_zext);
           }
           ty::ty_int | ty::ty_machine(ast::ty_i32) |
                 ty::ty_machine(ast::ty_u32) {
-            ret tup(ccx.upcalls.log_int, us_imm);
+            ret rec(val=ccx.upcalls.log_int, st=us_imm);
           }
           ty::ty_istr {
-            ret tup(ccx.upcalls.log_istr, us_alias_istr);
+            ret rec(val=ccx.upcalls.log_istr, st=us_alias_istr);
           }
           _ {
             ccx.sess.span_unimpl(sp, "logging for values of type " +
@@ -379,7 +379,7 @@ fn trans_log(&@block_ctxt cx, &span sp, int level, &@ast::expr expr)
 
     auto expr_t = ty::expr_ty(bcx_tcx(log_bcx), expr);
     auto r = get_upcall(bcx_ccx(bcx), sp, expr_t);
-    auto llupcall = r._0; auto style = r._1;
+    auto llupcall = r.val; auto style = r.st;
 
     auto arg_dest;
     alt (style) {
@@ -415,7 +415,7 @@ fn trans_path(&@block_ctxt bcx, &dest dest, &ast::path path, ast::node_id id)
         -> @block_ctxt {
     alt (bcx_tcx(bcx).def_map.get(id)) {
       ast::def_local(?def_id) {
-        alt (bcx_fcx(bcx).lllocals.find(def_id._1)) {
+        alt (bcx_fcx(bcx).lllocals.find(def_id.node)) {
           none { bcx_ccx(bcx).sess.unimpl("upvar in trans_path"); }
           some(?llptr) {
             // TODO: Copy hooks.
@@ -481,7 +481,7 @@ fn trans_block(&@block_ctxt cx, &dest dest, &ast::blk blk)
 // If |expand| is true, we never spill to the heap. This should be used
 // whenever the destination size isn't fixed.
 fn trans_lit_str_common(&@crate_ctxt ccx, &str s, bool expand)
-        -> tup(ValueRef, option[ValueRef]) {
+        -> rec(ValueRef stack, option[ValueRef] heap) {
     auto llstackpart; auto llheappartopt;
 
     auto len = str::byte_len(s);
@@ -515,8 +515,8 @@ fn trans_lit_str_common(&@crate_ctxt ccx, &str s, bool expand)
                                       llheappart));
     }
 
-    ret tup(mk_const(ccx, "const_istr_stack", false, llstackpart),
-            llheappartopt);
+    ret rec(stack=mk_const(ccx, "const_istr_stack", false, llstackpart),
+            heap=llheappartopt);
 }
 
 // As above, we don't use destination-passing style here.
diff --git a/src/comp/middle/trans_vec.rs b/src/comp/middle/trans_vec.rs
index 1707c085869..2105fd87287 100644
--- a/src/comp/middle/trans_vec.rs
+++ b/src/comp/middle/trans_vec.rs
@@ -39,7 +39,7 @@ import tc = middle::trans_common;
 // TODO: We can optimize this in the cases in which we statically know the
 // vector must be on the stack.
 fn get_len_and_data(&@block_ctxt cx, ty::t t, ValueRef llvecptr)
-        -> tup(@block_ctxt, ValueRef, ValueRef) {
+        -> rec(@block_ctxt bcx, ValueRef len, ValueRef data) {
     auto bcx = cx;
 
     // If this interior vector has dynamic size, we can't assume anything
@@ -115,7 +115,7 @@ fn get_len_and_data(&@block_ctxt cx, ty::t t, ValueRef llvecptr)
                           ~[stack_elem, zero_elem, heap_elem],
                           ~[bcx.llbb, zero_len_cx.llbb,
                             nonzero_len_cx.llbb]);
-    ret tup(next_cx, len, elem);
+    ret rec(bcx=next_cx, len=len, data=elem);
 }
 
 fn trans_concat(&@block_ctxt cx, &dest in_dest, &span sp, ty::t t,
@@ -139,15 +139,15 @@ fn trans_concat(&@block_ctxt cx, &dest in_dest, &span sp, ty::t t,
     auto llrhsptr = trans_dps::dest_ptr(rhs_tmp);
 
     auto r0 = get_len_and_data(bcx, t, lllhsptr);
-    bcx = r0._0; auto lllhslen = r0._1; auto lllhsdata = r0._2;
+    bcx = r0.bcx; auto lllhslen = r0.len; auto lllhsdata = r0.data;
     r0 = get_len_and_data(bcx, t, llrhsptr);
-    bcx = r0._0; auto llrhslen = r0._1; auto llrhsdata = r0._2;
+    bcx = r0.bcx; auto llrhslen = r0.len; auto llrhsdata = r0.data;
 
     if skip_null { lllhslen = bcx.build.Sub(lllhslen, C_int(1)); }
 
     // Allocate the destination.
     auto r1 = trans_dps::spill_alias(bcx, in_dest, t);
-    bcx = r1._0; auto dest = r1._1;
+    bcx = r1.bcx; auto dest = r1.dest;
 
     auto unit_t = ty::sequence_element_type(bcx_tcx(bcx), t);
     auto unit_sz = trans_dps::size_of(bcx_ccx(bcx), sp, unit_t);
diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs
index 7e01ed3ca78..6a527d50eb6 100644
--- a/src/comp/middle/tstate/auxiliary.rs
+++ b/src/comp/middle/tstate/auxiliary.rs
@@ -55,7 +55,7 @@ tag oper_type {
 
 /* logging funs */
 fn def_id_to_str(def_id d) -> str {
-    ret int::str(d._0) + "," + int::str(d._1);
+    ret int::str(d.crate) + "," + int::str(d.node);
 }
 
 fn comma_str(&(@constr_arg_use)[] args) -> str {
@@ -65,7 +65,7 @@ fn comma_str(&(@constr_arg_use)[] args) -> str {
         if (comma) { rslt += ", "; } else { comma = true; }
         alt (a.node) {
             case (carg_base) { rslt += "*"; }
-            case (carg_ident(?i)) { rslt += i._0; }
+            case (carg_ident(?i)) { rslt += i.ident; }
             case (carg_lit(?l)) { rslt += lit_to_str(l); }
         }
     }
@@ -503,7 +503,7 @@ fn node_id_to_def(&crate_ctxt ccx, node_id id) -> option::t[def] {
 fn norm_a_constraint(def_id id, &constraint c) -> norm_constraint[] {
     alt (c) {
         case (cinit(?n, ?sp, ?i)) {
-            ret ~[rec(bit_num=n, c=respan(sp, ninit(id._1, i)))];
+            ret ~[rec(bit_num=n, c=respan(sp, ninit(id.node, i)))];
         }
         case (cpred(?p, ?descs)) {
             let norm_constraint[] rslt = ~[];
@@ -522,8 +522,9 @@ fn norm_a_constraint(def_id id, &constraint c) -> norm_constraint[] {
 // non-exhaustive match in trans.
 fn constraints(&fn_ctxt fcx) -> norm_constraint[] {
     let norm_constraint[] rslt = ~[];
-    for each (@tup(def_id, constraint) p in fcx.enclosing.constrs.items()) {
-        rslt += norm_a_constraint(p._0, p._1);
+    for each (@rec(def_id key, constraint val) p
+              in fcx.enclosing.constrs.items()) {
+        rslt += norm_a_constraint(p.key, p.val);
     }
     ret rslt;
 }
@@ -535,11 +536,11 @@ fn match_args(&fn_ctxt fcx, &(@mutable pred_args[]) occs,
               &(@constr_arg_use)[] occ) ->
    uint {
     log "match_args: looking at " +
-        constr_args_to_str(std::util::fst[ident, node_id], occ);
+        constr_args_to_str(fn(&inst i) -> str { ret i.ident; }, occ);
     for (pred_args pd in *occs) {
         log "match_args: candidate " + pred_args_to_str(pd);
         fn eq(&inst p, &inst q) -> bool {
-            ret p._1 == q._1;
+            ret p.node == q.node;
         }
         if (ty::args_eq(eq, pd.node.args, occ)) { ret pd.node.bit_num; }
     }
@@ -563,12 +564,14 @@ fn expr_to_constr_arg(ty::ctxt tcx, &@expr e) -> @constr_arg_use {
         case (expr_path(?p)) {
             alt (tcx.def_map.find(e.id)) {
                 case (some(def_local(?l_id))) {
-                    ret @respan(p.span, carg_ident(tup(p.node.idents.(0),
-                                                       l_id._1)));
+                    ret @respan(p.span,
+                                carg_ident(rec(ident=p.node.idents.(0),
+                                               node=l_id.node)));
                 }
                 case (some(def_arg(?a_id))) {
-                    ret @respan(p.span, carg_ident(tup(p.node.idents.(0),
-                                                       a_id._1)));
+                    ret @respan(p.span,
+                                carg_ident(rec(ident=p.node.idents.(0),
+                                               node=a_id.node)));
                 }
                 case (_) {
                     tcx.sess.bug("exprs_to_constr_args: non-local variable " +
@@ -625,7 +628,7 @@ fn expr_to_constr(ty::ctxt tcx, &@expr e) -> sp_constr {
 
 fn pred_args_to_str(&pred_args p) -> str {
     "<" + uint::str(p.node.bit_num) + ", " +
-        constr_args_to_str(std::util::fst[ident, node_id],
+        constr_args_to_str(fn(&inst i) -> str { ret i.ident; },
                            p.node.args) + ">"
 }
 
@@ -664,7 +667,7 @@ fn pred_args_matches(&(constr_arg_general_[inst])[] pattern,
             case (carg_ident(?p)) {
                 alt (n) {
                     case (carg_ident(?q)) {
-                        if (p._1 != q._1) {
+                        if (p.node != q.node) {
                             ret false;
                         }
                     }
@@ -702,13 +705,13 @@ fn find_instance_(&(constr_arg_general_[inst])[] pattern,
     ret none;
 }
 
-type inst = tup(ident, node_id);
-type subst = tup(inst, inst)[];
+type inst = rec(ident ident, node_id node);
+type subst = rec(inst from, inst to)[];
 
 fn find_instances(&fn_ctxt fcx, &subst subst, &constraint c)
-        -> (tup(uint, uint))[] {
+        -> (rec(uint from, uint to))[] {
 
-    let (tup(uint, uint))[] rslt = ~[];
+    auto rslt = ~[];
     if (ivec::len(subst) == 0u) {
         ret rslt;
     }
@@ -722,7 +725,7 @@ fn find_instances(&fn_ctxt fcx, &subst subst, &constraint c)
                     auto new = replace(subst, d);
                     alt (find_instance_(new, *descs)) {
                         case (some(?d1)) {
-                            rslt += ~[tup(old_bit_num, d1)];
+                            rslt += ~[rec(from=old_bit_num, to=d1)];
                         }
                         case (_) { }
                     }
@@ -734,9 +737,9 @@ fn find_instances(&fn_ctxt fcx, &subst subst, &constraint c)
 }
 
 fn find_in_subst(node_id id, &subst s) -> option::t[inst] {
-    for (tup(inst, inst) p in s) {
-        if (id == p._0._1) {
-            ret some(p._1);
+    for (rec(inst from, inst to) p in s) {
+        if (id == p.from.node) {
+            ret some(p.to);
         }
     }
     ret none;
@@ -750,7 +753,7 @@ fn insts_to_str(&(constr_arg_general_[inst])[] stuff) -> str {
     auto rslt = "<";
     for (constr_arg_general_[inst] i in stuff) {
         rslt += " " + alt(i) {
-            case (carg_ident(?p)) { p._0 }
+            case (carg_ident(?p)) { p.ident }
             case (carg_base) { "*" }
             case (carg_lit(_)) { "[lit]" } } + " ";
     }
@@ -763,7 +766,7 @@ fn replace(subst subst, pred_args d) -> (constr_arg_general_[inst])[] {
     for (@constr_arg_use c in d.node.args) {
         alt (c.node) {
             case (carg_ident(?p)) {
-                alt (find_in_subst(p._1, subst)) {
+                alt (find_in_subst(p.node, subst)) {
                     case (some(?new)) {
                         rslt += ~[carg_ident(new)];
                     }
@@ -840,8 +843,8 @@ fn local_node_id_to_def_id(&fn_ctxt fcx, &node_id i) -> option::t[def_id] {
 fn local_node_id_to_local_def_id(&fn_ctxt fcx, &node_id i)
     -> option::t[node_id] {
     alt (local_node_id_to_def(fcx, i)) {
-        case (some (def_local(?d_id))) { some(d_id._1) }
-        case (some (def_arg(?a_id)))  { some(a_id._1) }
+        case (some (def_local(?d_id))) { some(d_id.node) }
+        case (some (def_arg(?a_id)))  { some(a_id.node) }
         case (_)                      { none }
     }
 }
@@ -870,26 +873,25 @@ fn copy_in_poststate_two(&fn_ctxt fcx, &poststate src_post,
     auto subst;
     alt (ty) {
         case (oper_swap) {
-            subst = ~[tup(dest, src),
-                     tup(src, dest)];
+            subst = ~[rec(from=dest, to=src),
+                      rec(from=src, to=dest)];
         }
         case (oper_assign_op) {
             ret; // Don't do any propagation
         }
         case (_) {
-            subst = ~[tup(src, dest)];
+            subst = ~[rec(from=src, to=dest)];
         }
     }
 
-    for each (@tup(def_id, constraint) p in
+    for each (@rec(def_id key, constraint val) p in
               fcx.enclosing.constrs.items()) {
         // replace any occurrences of the src def_id with the
         // dest def_id
-        auto instances = find_instances(fcx, subst, p._1);
-
-        for (tup(uint,uint) p in instances) {
-            if (promises_(p._0, src_post)) {
-                set_in_poststate_(p._1, target_post);
+        auto insts = find_instances(fcx, subst, p.val);
+        for (rec(uint from, uint to) p in insts) {
+            if (promises_(p.from, src_post)) {
+                set_in_poststate_(p.to, target_post);
             }
         }
     }
@@ -1020,7 +1022,7 @@ fn args_mention[T](&(@constr_arg_use)[] args, fn(&(T)[], node_id) -> bool q,
     for (@constr_arg_use a in args) {
         alt (a.node) {
             case (carg_ident(?p1)) {
-                if (q(s, p1._1)) {
+                if (q(s, p1.node)) {
                     ret true;
                 }
             }
@@ -1058,7 +1060,7 @@ fn do_nothing[T](&_fn f, &ty_param[] tp, &span sp, &fn_ident i,
 fn args_to_constr_args(&span sp, &arg[] args) -> (@constr_arg_use)[] {
     let (@constr_arg_use)[] actuals = ~[];
     for (arg a in args) {
-        actuals += ~[@respan(sp, carg_ident(tup(a.ident, a.id)))];
+        actuals += ~[@respan(sp, carg_ident(rec(ident=a.ident, node=a.id)))];
     }
     ret actuals;
 }
diff --git a/src/comp/middle/tstate/bitvectors.rs b/src/comp/middle/tstate/bitvectors.rs
index 0f96a7e5662..c9cf002d949 100644
--- a/src/comp/middle/tstate/bitvectors.rs
+++ b/src/comp/middle/tstate/bitvectors.rs
@@ -213,7 +213,7 @@ fn clear_in_poststate_expr(&fn_ctxt fcx, &@expr e, &poststate t) {
                     alt (local_node_id_to_def(fcx, e.id)) {
                         case (some(def_local(?d_id))) {
                             clear_in_poststate_(
-                               bit_num(fcx,ninit(d_id._1, i)), t);
+                               bit_num(fcx,ninit(d_id.node, i)), t);
                         }
                         case (some(_)) { /* ignore args (for now...) */ }
                         case (_) {
diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs
index faeceddf3c2..79c4e595d51 100644
--- a/src/comp/middle/tstate/pre_post_conditions.rs
+++ b/src/comp/middle/tstate/pre_post_conditions.rs
@@ -219,7 +219,7 @@ fn gen_if_local(&fn_ctxt fcx, @expr lhs, @expr rhs, node_id larger_id,
                     set_pre_and_post(fcx.ccx, larger_id, p.precondition,
                                      p.postcondition);
                     gen(fcx, larger_id,
-                        ninit(d_id._1, path_to_ident(fcx.ccx.tcx, pth)));
+                        ninit(d_id.node, path_to_ident(fcx.ccx.tcx, pth)));
                 }
                 case (_) { find_pre_post_exprs(fcx, ~[lhs, rhs], larger_id); }
             }
@@ -255,7 +255,7 @@ fn handle_update(&fn_ctxt fcx, &@expr parent,
                     alt (df) {
                         case (def_local(?d_id)) {
                             auto i =
-                                bit_num(fcx, ninit(d_id._1,
+                                bit_num(fcx, ninit(d_id.node,
                                         path_to_ident(fcx.ccx.tcx, p)));
                             require_and_preserve(i, expr_pp(fcx.ccx, lhs));
                         }
@@ -274,11 +274,13 @@ fn handle_update(&fn_ctxt fcx, &@expr parent,
                             alt (d1) {
                                 case (some(?id1)) {
                                     auto instlhs =
-                                        tup(path_to_ident(fcx.ccx.tcx,
-                                                          p), id);
+                                        rec(ident=path_to_ident
+                                            (fcx.ccx.tcx, p),
+                                            node=id);
                                     auto instrhs =
-                                        tup(path_to_ident(fcx.ccx.tcx,
-                                                          p1), id1);
+                                        rec(ident=path_to_ident
+                                            (fcx.ccx.tcx, p1),
+                                            node=id1);
                                     copy_in_poststate_two(fcx, tmp,
                                         post, instlhs, instrhs, ty);
                                 }
@@ -343,8 +345,8 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
                 case (def_local(?d_id)) {
                     auto i =
                         bit_num(fcx,
-                          ninit(d_id._1, path_to_ident(fcx.ccx.tcx, p)));
-                    use_var(fcx, d_id._1);
+                          ninit(d_id.node, path_to_ident(fcx.ccx.tcx, p)));
+                    use_var(fcx, d_id.node);
                     require_and_preserve(i, rslt);
                 }
                 case (_) {/* nothing to check */ }
@@ -603,10 +605,10 @@ fn find_pre_post_stmt(&fn_ctxt fcx, &stmt s) {
                             alt (an_init.expr.node) {
                                 case (expr_path(?p)) {
                                     copy_in_postcond(fcx, id,
-                                      tup(alocal.node.ident,
-                                          alocal.node.id),
-                                      tup(path_to_ident(fcx.ccx.tcx, p),
-                                          an_init.expr.id),
+                                      rec(ident=alocal.node.ident,
+                                          node=alocal.node.id),
+                                      rec(ident=path_to_ident(fcx.ccx.tcx, p),
+                                          node=an_init.expr.id),
                                        op_to_oper_ty(an_init.op));
                                 }
                                 case (_) {}
diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs
index 5161574eed2..ee7796453b9 100644
--- a/src/comp/middle/tstate/states.rs
+++ b/src/comp/middle/tstate/states.rs
@@ -54,7 +54,7 @@ import util::common::log_stmt_err;
 import util::common::log_expr_err;
 
 fn seq_states(&fn_ctxt fcx, prestate pres, &(@expr)[] exprs) ->
-   tup(bool, poststate) {
+   rec(bool changed, poststate post) {
     auto changed = false;
     auto post = pres;
     for (@expr e in exprs) {
@@ -63,7 +63,7 @@ fn seq_states(&fn_ctxt fcx, prestate pres, &(@expr)[] exprs) ->
         // log_err changed;
         post = expr_poststate(fcx.ccx, e);
     }
-    ret tup(changed, post);
+    ret rec(changed=changed, post=post);
 }
 
 fn find_pre_post_state_sub(&fn_ctxt fcx, &prestate pres, &@expr e,
@@ -128,11 +128,13 @@ fn find_pre_post_state_two(&fn_ctxt fcx, &prestate pres, &@expr lhs,
                             alt (d1) {
                                 case (some(?id1)) {
                                     auto instlhs =
-                                        tup(path_to_ident(fcx.ccx.tcx,
-                                                          p), id);
+                                        rec(ident=path_to_ident
+                                            (fcx.ccx.tcx, p),
+                                            node=id);
                                     auto instrhs =
-                                        tup(path_to_ident(fcx.ccx.tcx,
-                                                          p1), id1);
+                                        rec(ident=path_to_ident
+                                            (fcx.ccx.tcx, p1),
+                                            node=id1);
                                     copy_in_poststate_two(fcx, tmp,
                                             post, instlhs, instrhs, ty);
                                 }
@@ -162,7 +164,7 @@ fn find_pre_post_state_call(&fn_ctxt fcx, &prestate pres, &@expr a,
 fn find_pre_post_state_exprs(&fn_ctxt fcx, &prestate pres, node_id id,
                              &(@expr)[] es, controlflow cf) -> bool {
     auto rs = seq_states(fcx, pres, es);
-    auto changed = rs._0 | set_prestate_ann(fcx.ccx, id, pres);
+    auto changed = rs.changed | set_prestate_ann(fcx.ccx, id, pres);
     /* if this is a failing call, it sets everything as initialized */
     alt (cf) {
         case (noreturn) {
@@ -170,7 +172,7 @@ fn find_pre_post_state_exprs(&fn_ctxt fcx, &prestate pres, node_id id,
                 (fcx.ccx, id, false_postcond(num_constraints(fcx.enclosing)));
         }
         case (_) {
-            changed |= set_poststate_ann(fcx.ccx, id, rs._1);
+            changed |= set_poststate_ann(fcx.ccx, id, rs.post);
         }
     }
     ret changed;
@@ -208,7 +210,7 @@ fn gen_if_local(&fn_ctxt fcx, &poststate p, &@expr e) -> bool {
         case (expr_path(?pth)) {
             alt (node_id_to_def(fcx.ccx, e.id)) {
                 case (some(def_local(?loc))) {
-                    ret set_in_poststate_ident(fcx, loc._1,
+                    ret set_in_poststate_ident(fcx, loc.node,
                            path_to_ident(fcx.ccx.tcx, pth), p);
                 }
             case (_) { ret false; }
@@ -612,15 +614,16 @@ fn find_pre_post_state_stmt(&fn_ctxt fcx, &prestate pres, @stmt s) -> bool {
                                 case (expr_path(?p)) {
 
                                     auto instlhs =
-                                        tup(alocal.node.ident,
-                                            alocal.node.id);
+                                        rec(ident=alocal.node.ident,
+                                            node=alocal.node.id);
                                     auto rhs_d = local_node_id_to_local_def_id
                                         (fcx, an_init.expr.id);
                                     alt (rhs_d) {
                                         case (some(?rhsid)) {
                                             auto instrhs =
-                                                tup(path_to_ident(fcx.ccx.tcx,
-                                                                  p), rhsid);
+                                                rec(ident=path_to_ident
+                                                    (fcx.ccx.tcx, p),
+                                                    node=rhsid);
                                             copy_in_poststate(fcx, post,
                                                instlhs, instrhs,
                                                op_to_oper_ty(an_init.op));
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index d689c62d6df..fcd5d6a8b5d 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -204,7 +204,7 @@ type mt = rec(t ty, ast::mutability mut);
 
 // Contains information needed to resolve types and (in the future) look up
 // the types of AST nodes.
-type creader_cache = hashmap[tup(int, uint, uint), ty::t];
+type creader_cache = hashmap[rec(int cnum, uint pos, uint len), ty::t];
 
 type ctxt =
     @rec(@type_store ts,
@@ -304,7 +304,7 @@ tag type_err {
     terr_constr_mismatch(@type_constr, @type_constr);
 }
 
-type ty_param_count_and_ty = tup(uint, t);
+type ty_param_count_and_ty = rec(uint count, t ty);
 
 type type_cache = hashmap[ast::def_id, ty_param_count_and_ty];
 
@@ -354,7 +354,7 @@ const uint idx_first_others = 21u;
 
 type type_store = interner::interner[@raw_t];
 
-type ty_param_substs_opt_and_ty = tup(option::t[ty::t[]], ty::t);
+type ty_param_substs_opt_and_ty = rec(option::t[ty::t[]] substs, ty::t ty);
 
 type node_type_table =
     @smallintmap::smallintmap[ty::ty_param_substs_opt_and_ty];
@@ -385,12 +385,13 @@ fn populate_type_store(&ctxt cx) {
 }
 
 fn mk_rcache() -> creader_cache {
-    fn hash_cache_entry(&tup(int, uint, uint) k) -> uint {
-        ret (k._0 as uint) + k._1 + k._2;
+    type val = rec(int cnum, uint pos, uint len);
+    fn hash_cache_entry(&val k) -> uint {
+        ret (k.cnum as uint) + k.pos + k.len;
     }
-    fn eq_cache_entries(&tup(int, uint, uint) a, &tup(int, uint, uint) b) ->
+    fn eq_cache_entries(&val a, &val b) ->
        bool {
-        ret a._0 == b._0 && a._1 == b._1 && a._2 == b._2;
+        ret a.cnum == b.cnum && a.pos == b.pos && a.len == b.len;
     }
     ret map::mk_hashmap(hash_cache_entry, eq_cache_entries);
 }
@@ -1300,8 +1301,8 @@ fn hash_type_structure(&sty st) -> uint {
     }
     fn hash_def(uint id, ast::def_id did) -> uint {
         auto h = id;
-        h += h << 5u + (did._0 as uint);
-        h += h << 5u + (did._1 as uint);
+        h += h << 5u + (did.crate as uint);
+        h += h << 5u + (did.node as uint);
         ret h;
     }
     fn hash_subty(uint id, &t subty) -> uint {
@@ -1505,7 +1506,7 @@ fn equal_type_structures(&sty a, &sty b) -> bool {
         ret true;
     }
     fn equal_def(&ast::def_id did_a, &ast::def_id did_b) -> bool {
-        ret did_a._0 == did_b._0 && did_a._1 == did_b._1;
+        ret did_a.crate == did_b.crate && did_a.node == did_b.node;
     }
     alt (a) {
         case (ty_nil) {
@@ -1708,7 +1709,7 @@ fn equal_type_structures(&sty a, &sty b) -> bool {
         case (ty_native(?a_id)) {
             alt (b) {
                 case (ty_native(?b_id)) {
-                    ret a_id._0 == b_id._0 && a_id._1 == b_id._1;
+                    ret a_id.crate == b_id.crate && a_id.node == b_id.node;
                 }
                 case (_) { ret false; } }
         }
@@ -1766,11 +1767,11 @@ fn node_id_to_ty_param_substs_opt_and_ty(&ctxt cx, &ast::node_id id) ->
 }
 
 fn node_id_to_type(&ctxt cx, &ast::node_id id) -> t {
-    ret node_id_to_ty_param_substs_opt_and_ty(cx, id)._1;
+    ret node_id_to_ty_param_substs_opt_and_ty(cx, id).ty;
 }
 
 fn node_id_to_type_params(&ctxt cx, &ast::node_id id) -> t[] {
-    alt (node_id_to_ty_param_substs_opt_and_ty(cx, id)._0) {
+    alt (node_id_to_ty_param_substs_opt_and_ty(cx, id).substs) {
         case (none)       { ret ~[]; }
         case (some(?tps)) { ret tps; }
     }
@@ -1778,17 +1779,16 @@ fn node_id_to_type_params(&ctxt cx, &ast::node_id id) -> t[] {
 
 fn node_id_has_type_params(&ctxt cx, &ast::node_id id) -> bool {
     auto tpt = node_id_to_ty_param_substs_opt_and_ty(cx, id);
-    ret !option::is_none[t[]](tpt._0);
+    ret !option::is_none[t[]](tpt.substs);
 }
 
 
 // Returns a type with type parameter substitutions performed if applicable.
-fn ty_param_substs_opt_and_ty_to_monotype(&ctxt cx,
-                                          &ty_param_substs_opt_and_ty tpot) ->
-   t {
-    alt (tpot._0) {
-        case (none) { ret tpot._1; }
-        case (some(?tps)) { ret substitute_type_params(cx, tps, tpot._1); }
+fn ty_param_substs_opt_and_ty_to_monotype
+    (&ctxt cx, &ty_param_substs_opt_and_ty tpot) -> t {
+    alt (tpot.substs) {
+        case (none) { ret tpot.ty; }
+        case (some(?tps)) { ret substitute_type_params(cx, tps, tpot.ty); }
     }
 }
 
@@ -1896,9 +1896,10 @@ fn expr_ty(&ctxt cx, &@ast::expr expr) -> t {
     ret node_id_to_monotype(cx, expr.id);
 }
 
-fn expr_ty_params_and_ty(&ctxt cx, &@ast::expr expr) -> tup(t[], t) {
-    ret tup(node_id_to_type_params(cx, expr.id),
-            node_id_to_type(cx, expr.id));
+fn expr_ty_params_and_ty(&ctxt cx, &@ast::expr expr)
+    -> rec(t[] params, t ty) {
+    ret rec(params=node_id_to_type_params(cx, expr.id),
+            ty=node_id_to_type(cx, expr.id));
 }
 
 fn expr_has_ty_params(&ctxt cx, &@ast::expr expr) -> bool {
@@ -2409,7 +2410,8 @@ mod unify {
             case (ty::ty_native(?ex_id)) {
                 alt (struct(cx.tcx, actual)) {
                     case (ty_native(?act_id)) {
-                        if (ex_id._0 == act_id._0 && ex_id._1 == act_id._1) {
+                        if (ex_id.crate == act_id.crate &&
+                            ex_id.node == act_id.node) {
                             ret ures_ok(actual);
                         } else {
                             ret ures_err(terr_mismatch);
@@ -2422,8 +2424,8 @@ mod unify {
             case (ty::ty_tag(?expected_id, ?expected_tps)) {
                 alt (struct(cx.tcx, actual)) {
                     case (ty::ty_tag(?actual_id, ?actual_tps)) {
-                        if (expected_id._0 != actual_id._0 ||
-                                expected_id._1 != actual_id._1) {
+                        if (expected_id.crate != actual_id.crate ||
+                            expected_id.node != actual_id.node) {
                             ret ures_err(terr_mismatch);
                         }
                         // TODO: factor this cruft out, see the TODO in the
@@ -2551,7 +2553,8 @@ mod unify {
             case (ty::ty_res(?ex_id, ?ex_inner, ?ex_tps)) {
                 alt (struct(cx.tcx, actual)) {
                     case (ty::ty_res(?act_id, ?act_inner, ?act_tps)) {
-                        if (ex_id._0 != act_id._0 || ex_id._1 != act_id._1) {
+                        if (ex_id.crate != act_id.crate ||
+                            ex_id.node != act_id.node) {
                             ret ures_err(terr_mismatch);
                         }
                         auto result = unify_step(cx, ex_inner, act_inner);
@@ -2883,7 +2886,7 @@ fn type_err_to_str(&ty::type_err err) -> str {
 // Converts type parameters in a type to type variables and returns the
 // resulting type along with a list of type variable IDs.
 fn bind_params_in_type(&span sp, &ctxt cx, fn() -> int  next_ty_var, t typ,
-                       uint ty_param_count) -> tup(int[], t) {
+                       uint ty_param_count) -> rec(int[] ids, t ty) {
     let @mutable int[] param_var_ids = @mutable ~[];
     auto i = 0u;
     while (i < ty_param_count) {
@@ -2902,7 +2905,7 @@ fn bind_params_in_type(&span sp, &ctxt cx, fn() -> int  next_ty_var, t typ,
     auto new_typ =
         fold_ty(cx, fm_param(bind binder(sp, cx, param_var_ids,
                                          next_ty_var, _)), typ);
-    ret tup(*param_var_ids, new_typ);
+    ret rec(ids=*param_var_ids, ty=new_typ);
 }
 
 
@@ -2940,8 +2943,10 @@ fn def_has_ty_params(&ast::def def) -> bool {
 type variant_info = rec(ty::t[] args, ty::t ctor_ty, ast::def_id id);
 
 fn tag_variants(&ctxt cx, &ast::def_id id) -> variant_info[] {
-    if (ast::local_crate != id._0) { ret csearch::get_tag_variants(cx, id); }
-    auto item = alt (cx.items.find(id._1)) {
+    if (ast::local_crate != id.crate) {
+        ret csearch::get_tag_variants(cx, id);
+    }
+    auto item = alt (cx.items.find(id.node)) {
         case (some(?i)) { i }
         case (none) {
             cx.sess.bug("expected to find cached node_item")
@@ -2992,7 +2997,7 @@ fn tag_variant_with_id(&ctxt cx, &ast::def_id tag_id, &ast::def_id variant_id)
 // If the given item is in an external crate, looks up its type and adds it to
 // the type cache. Returns the type parameters and type.
 fn lookup_item_type(ctxt cx, ast::def_id did) -> ty_param_count_and_ty {
-    if (did._0 == ast::local_crate) {
+    if (did.crate == ast::local_crate) {
         // The item is in this crate. The caller should have added it to the
         // type cache already; we simply return it.
 
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index b56afe3d705..3fac0bfbf56 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -101,20 +101,22 @@ fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) ->
    ty_param_count_and_ty {
     alt (defn) {
         case (ast::def_arg(?id)) {
-            assert (fcx.locals.contains_key(id._1));
+            assert (fcx.locals.contains_key(id.node));
             auto typ = ty::mk_var(fcx.ccx.tcx,
-                                  lookup_local(fcx, sp, id._1));
-            ret tup(0u, typ);
+                                  lookup_local(fcx, sp, id.node));
+            ret rec(count=0u, ty=typ);
         }
         case (ast::def_local(?id)) {
-            assert (fcx.locals.contains_key(id._1));
-            auto typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id._1));
-            ret tup(0u, typ);
+            assert (fcx.locals.contains_key(id.node));
+            auto typ = ty::mk_var(fcx.ccx.tcx,
+                                  lookup_local(fcx, sp, id.node));
+            ret rec(count=0u, ty=typ);
         }
         case (ast::def_obj_field(?id)) {
-            assert (fcx.locals.contains_key(id._1));
-            auto typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id._1));
-            ret tup(0u, typ);
+            assert (fcx.locals.contains_key(id.node));
+            auto typ = ty::mk_var(fcx.ccx.tcx,
+                                  lookup_local(fcx, sp, id.node));
+            ret rec(count=0u, ty=typ);
         }
         case (ast::def_fn(?id, _)) {
             ret ty::lookup_item_type(fcx.ccx.tcx, id);
@@ -129,15 +131,16 @@ fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) ->
             ret ty::lookup_item_type(fcx.ccx.tcx, vid);
         }
         case (ast::def_binding(?id)) {
-            assert (fcx.locals.contains_key(id._1));
-            auto typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id._1));
-            ret tup(0u, typ);
+            assert (fcx.locals.contains_key(id.node));
+            auto typ = ty::mk_var(fcx.ccx.tcx,
+                                  lookup_local(fcx, sp, id.node));
+            ret rec(count=0u, ty=typ);
         }
         case (ast::def_mod(_)) {
             // Hopefully part of a path.
             // TODO: return a type that's more poisonous, perhaps?
 
-            ret tup(0u, ty::mk_nil(fcx.ccx.tcx));
+            ret rec(count=0u, ty=ty::mk_nil(fcx.ccx.tcx));
         }
         case (ast::def_ty(_)) {
             fcx.ccx.tcx.sess.span_fatal(sp, "expected value but found type");
@@ -155,11 +158,11 @@ fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) ->
 // number of type parameters and type.
 fn instantiate_path(&@fn_ctxt fcx, &ast::path pth, &ty_param_count_and_ty tpt,
                     &span sp) -> ty_param_substs_opt_and_ty {
-    auto ty_param_count = tpt._0;
+    auto ty_param_count = tpt.count;
     auto bind_result =
-        bind_params_in_type(sp, fcx.ccx.tcx, bind next_ty_var_id(fcx), tpt._1,
+        bind_params_in_type(sp, fcx.ccx.tcx, bind next_ty_var_id(fcx), tpt.ty,
                             ty_param_count);
-    auto ty_param_vars = bind_result._0;
+    auto ty_param_vars = bind_result.ids;
     auto ty_substs_opt;
     auto ty_substs_len = ivec::len[@ast::ty](pth.node.types);
     if (ty_substs_len > 0u) {
@@ -201,7 +204,7 @@ fn instantiate_path(&@fn_ctxt fcx, &ast::path pth, &ty_param_count_and_ty tpt,
         }
         ty_substs_opt = some[ty::t[]](ty_substs);
     }
-    ret tup(ty_substs_opt, tpt._1);
+    ret rec(substs=ty_substs_opt, ty=tpt.ty);
 }
 
 fn ast_mode_to_mode(ast::mode mode) -> ty::mode {
@@ -275,7 +278,7 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t {
         // "foo = int" like OCaml?
 
         auto params_opt_and_ty = getter(id);
-        if (params_opt_and_ty._0 == 0u) { ret params_opt_and_ty._1; }
+        if (params_opt_and_ty.count == 0u) { ret params_opt_and_ty.ty; }
         // The typedef is type-parametric. Do the type substitution.
         //
 
@@ -284,14 +287,14 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t {
             param_bindings += ~[ast_ty_to_ty(tcx, getter, ast_ty)];
         }
         if (ivec::len(param_bindings) !=
-                ty::count_ty_params(tcx, params_opt_and_ty._1)) {
+            ty::count_ty_params(tcx, params_opt_and_ty.ty)) {
             tcx.sess.span_fatal(sp,
                                 "Wrong number of type arguments for a \
                                 polymorphic tag");
         }
         auto typ =
             ty::substitute_type_params(tcx, param_bindings,
-                                       params_opt_and_ty._1);
+                                       params_opt_and_ty.ty);
         ret typ;
     }
     auto typ;
@@ -357,7 +360,7 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t {
                     typ = instantiate(tcx, ast_ty.span, getter, id,
                                       path.node.types);
                 }
-                case (some(ast::def_native_ty(?id))) { typ = getter(id)._1; }
+                case (some(ast::def_native_ty(?id))) { typ = getter(id).ty; }
                 case (some(ast::def_ty_arg(?id))) {
                     typ = ty::mk_param(tcx, id);
                 }
@@ -434,8 +437,8 @@ mod write {
     // Writes a type parameter count and type pair into the node type table.
     fn ty(&ty::ctxt tcx, ast::node_id node_id,
           &ty_param_substs_opt_and_ty tpot) {
-        assert (!ty::type_contains_vars(tcx, tpot._1));
-        ret inner(tcx.node_types, node_id, tpot);
+        assert (!ty::type_contains_vars(tcx, tpot.ty));
+        inner(tcx.node_types, node_id, tpot);
     }
 
     // Writes a type parameter count and type pair into the node type table.
@@ -444,30 +447,30 @@ mod write {
     fn ty_fixup(@fn_ctxt fcx, ast::node_id node_id,
                 &ty_param_substs_opt_and_ty tpot) {
         inner(fcx.ccx.tcx.node_types, node_id, tpot);
-        if (ty::type_contains_vars(fcx.ccx.tcx, tpot._1)) {
+        if (ty::type_contains_vars(fcx.ccx.tcx, tpot.ty)) {
             fcx.fixups += ~[node_id];
         }
     }
 
     // Writes a type with no type parameters into the node type table.
     fn ty_only(&ty::ctxt tcx, ast::node_id node_id, ty::t typ) {
-        ret ty(tcx, node_id, tup(none[ty::t[]], typ));
+        ty(tcx, node_id, rec(substs=none[ty::t[]], ty=typ));
     }
 
     // Writes a type with no type parameters into the node type table. This
     // function allows for the possibility of type variables.
     fn ty_only_fixup(@fn_ctxt fcx, ast::node_id node_id, ty::t typ) {
-        ret ty_fixup(fcx, node_id, tup(none[ty::t[]], typ));
+        ret ty_fixup(fcx, node_id, rec(substs=none[ty::t[]], ty=typ));
     }
 
     // Writes a nil type into the node type table.
     fn nil_ty(&ty::ctxt tcx, ast::node_id node_id) {
-        ret ty(tcx, node_id, tup(none[ty::t[]], ty::mk_nil(tcx)));
+        ret ty(tcx, node_id, rec(substs=none[ty::t[]], ty=ty::mk_nil(tcx)));
     }
 
     // Writes the bottom type into the node type table.
     fn bot_ty(&ty::ctxt tcx, ast::node_id node_id) {
-        ret ty(tcx, node_id, tup(none[ty::t[]], ty::mk_bot(tcx)));
+        ret ty(tcx, node_id, rec(substs=none[ty::t[]], ty=ty::mk_bot(tcx)));
     }
 }
 
@@ -515,7 +518,7 @@ mod collect {
             ty::mk_fn(cx.tcx, proto, input_tys, output_ty, decl.cf,
                       out_constrs);
         auto ty_param_count = ivec::len[ast::ty_param](ty_params);
-        auto tpt = tup(ty_param_count, t_fn);
+        auto tpt = rec(count=ty_param_count, ty=t_fn);
         alt (def_id) {
             case (some(?did)) { cx.tcx.tcache.insert(did, tpt); }
             case (_) { }
@@ -534,16 +537,16 @@ mod collect {
 
         auto t_fn = ty::mk_native_fn(cx.tcx, abi, input_tys, output_ty);
         auto ty_param_count = ivec::len[ast::ty_param](ty_params);
-        auto tpt = tup(ty_param_count, t_fn);
+        auto tpt = rec(count=ty_param_count, ty=t_fn);
         cx.tcx.tcache.insert(def_id, tpt);
         ret tpt;
     }
     fn getter(@ctxt cx, &ast::def_id id) -> ty::ty_param_count_and_ty {
-        if (id._0 != ast::local_crate) {
+        if (id.crate != ast::local_crate) {
             // This is a type we need to load in from the crate reader.
             ret csearch::get_type(cx.tcx, id);
         }
-        auto it = cx.tcx.items.find(id._1);
+        auto it = cx.tcx.items.find(id.node);
         auto tpt;
         alt (it) {
             case (some(ast_map::node_item(?item))) {
@@ -555,7 +558,7 @@ mod collect {
             }
             case (_) {
                 cx.tcx.sess.fatal("internal error " +
-                                  std::int::str(id._1));
+                                  std::int::str(id.node));
             }
         }
         ret tpt;
@@ -600,7 +603,7 @@ mod collect {
         auto methods = get_obj_method_types(cx, ob);
         auto t_obj = ty::mk_obj(cx.tcx, ty::sort_methods(methods));
         t_obj = ty::rename(cx.tcx, t_obj, id);
-        ret tup(ivec::len(ty_params), t_obj);
+        ret rec(count=ivec::len(ty_params), ty=t_obj);
     }
     fn ty_of_obj_ctor(@ctxt cx, &ast::ident id, &ast::_obj ob,
                       ast::node_id ctor_id, &ast::ty_param[] ty_params) ->
@@ -614,9 +617,9 @@ mod collect {
             t_inputs += ~[rec(mode=ty::mo_alias(false), ty=t_field)];
         }
 
-        auto t_fn = ty::mk_fn(cx.tcx, ast::proto_fn, t_inputs, t_obj._1,
+        auto t_fn = ty::mk_fn(cx.tcx, ast::proto_fn, t_inputs, t_obj.ty,
                               ast::return, ~[]);
-        auto tpt = tup(t_obj._0, t_fn);
+        auto tpt = rec(count=t_obj.count, ty=t_fn);
         cx.tcx.tcache.insert(local_def(ctor_id), tpt);
         ret tpt;
     }
@@ -626,7 +629,7 @@ mod collect {
         alt (it.node) {
             case (ast::item_const(?t, _)) {
                 auto typ = convert(t);
-                auto tpt = tup(0u, typ);
+                auto tpt = rec(count=0u, ty=typ);
                 cx.tcx.tcache.insert(local_def(it.id), tpt);
                 ret tpt;
             }
@@ -650,13 +653,14 @@ mod collect {
 
                 auto typ = convert(t);
                 auto ty_param_count = ivec::len[ast::ty_param](tps);
-                auto tpt = tup(ty_param_count, typ);
+                auto tpt = rec(count=ty_param_count, ty=typ);
                 cx.tcx.tcache.insert(local_def(it.id), tpt);
                 ret tpt;
             }
             case (ast::item_res(?f, _, ?tps, _)) {
                 auto t_arg = ty_of_arg(cx, f.decl.inputs.(0));
-                auto t_res = tup(ivec::len(tps), ty::mk_res
+                auto t_res = rec(count=ivec::len(tps),
+                                 ty=ty::mk_res
                                  (cx.tcx, local_def(it.id), t_arg.ty,
                                   mk_ty_params(cx, ivec::len(tps))));
                 cx.tcx.tcache.insert(local_def(it.id), t_res);
@@ -669,7 +673,7 @@ mod collect {
 
                 let ty::t[] subtys = mk_ty_params(cx, ty_param_count);
                 auto t = ty::mk_tag(cx.tcx, local_def(it.id), subtys);
-                auto tpt = tup(ty_param_count, t);
+                auto tpt = rec(count=ty_param_count, ty=t);
                 cx.tcx.tcache.insert(local_def(it.id), tpt);
                 ret tpt;
             }
@@ -693,7 +697,7 @@ mod collect {
                     case (none) { }
                 }
                 auto t = ty::mk_native(cx.tcx, ast::local_def(it.id));
-                auto tpt = tup(0u, t);
+                auto tpt = rec(count=0u, ty=t);
                 cx.tcx.tcache.insert(local_def(it.id), tpt);
                 ret tpt;
             }
@@ -728,7 +732,7 @@ mod collect {
                 result_ty = ty::mk_fn(cx.tcx, ast::proto_fn, args, tag_t,
                                       ast::return, ~[]);
             }
-            auto tpt = tup(ty_param_count, result_ty);
+            auto tpt = rec(count=ty_param_count, ty=result_ty);
             cx.tcx.tcache.insert(local_def(variant.node.id), tpt);
             write::ty_only(cx.tcx, variant.node.id, result_ty);
         }
@@ -755,7 +759,7 @@ mod collect {
             }
             case (ast::item_tag(?variants, ?ty_params)) {
                 auto tpt = ty_of_item(cx, it);
-                write::ty_only(cx.tcx, it.id, tpt._1);
+                write::ty_only(cx.tcx, it.id, tpt.ty);
                 get_tag_variant_types(cx, local_def(it.id), variants,
                                       ty_params);
             }
@@ -767,7 +771,7 @@ mod collect {
 
                 auto tpt =
                     ty_of_obj_ctor(cx, it.ident, object, ctor_id, ty_params);
-                write::ty_only(cx.tcx, ctor_id, tpt._1);
+                write::ty_only(cx.tcx, ctor_id, tpt.ty);
                 // Write the methods into the type table.
                 //
                 // FIXME: Inefficient; this ends up calling
@@ -787,7 +791,7 @@ mod collect {
                 // FIXME: We want to use uint::range() here, but that causes
                 // an assertion in trans.
 
-                auto args = ty::ty_fn_args(cx.tcx, tpt._1);
+                auto args = ty::ty_fn_args(cx.tcx, tpt.ty);
                 i = 0u;
                 while (i < ivec::len[ty::arg](args)) {
                     auto fld = object.fields.(i);
@@ -816,7 +820,7 @@ mod collect {
                 write::ty_only(cx.tcx, it.id, t_res);
                 write::ty_only(cx.tcx, ctor_id, t_ctor);
                 cx.tcx.tcache.insert(local_def(ctor_id),
-                                     tup(ivec::len(tps), t_ctor));
+                                     rec(count=ivec::len(tps), ty=t_ctor));
                 write::ty_only(cx.tcx, dtor_id, t_dtor);
             }
             case (_) {
@@ -825,7 +829,7 @@ mod collect {
                 // it into the node type table.
 
                 auto tpt = ty_of_item(cx, it);
-                write::ty_only(cx.tcx, it.id, tpt._1);
+                write::ty_only(cx.tcx, it.id, tpt.ty);
             }
         }
     }
@@ -843,7 +847,7 @@ mod collect {
 
             }
             case (ast::native_item_fn(_, _, _)) {
-                write::ty_only(cx.tcx, i.id, tpt._1);
+                write::ty_only(cx.tcx, i.id, tpt.ty);
             }
         }
     }
@@ -927,16 +931,16 @@ fn resolve_type_vars_if_possible(&@fn_ctxt fcx, ty::t typ) -> ty::t {
 
 // Demands - procedures that require that two types unify and emit an error
 // message if they don't.
-type ty_param_substs_and_ty = tup(ty::t[], ty::t);
+type ty_param_substs_and_ty = rec(ty::t[] substs, ty::t ty);
 
 mod demand {
     fn simple(&@fn_ctxt fcx, &span sp, &ty::t expected, &ty::t actual) ->
        ty::t {
-        ret full(fcx, sp, expected, actual, ~[], NO_AUTODEREF)._1;
+        ret full(fcx, sp, expected, actual, ~[], NO_AUTODEREF).ty;
     }
     fn autoderef(&@fn_ctxt fcx, &span sp, &ty::t expected, &ty::t actual,
                  autoderef_kind adk) -> ty::t {
-        ret full(fcx, sp, expected, actual, ~[], adk)._1;
+        ret full(fcx, sp, expected, actual, ~[], adk).ty;
     }
 
     // Requires that the two types unify, and prints an error message if they
@@ -972,8 +976,8 @@ mod demand {
                 auto tp_subst = ty::mk_var(fcx.ccx.tcx, var_id);
                 result_ty_param_substs += ~[tp_subst];
             }
-            ret tup(result_ty_param_substs,
-                    add_boxes(fcx.ccx, implicit_boxes, result_ty));
+            ret rec(substs=result_ty_param_substs,
+                    ty=add_boxes(fcx.ccx, implicit_boxes, result_ty));
         }
 
         alt (unify::simple(fcx, expected_1, actual_1)) {
@@ -1013,7 +1017,7 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid,
                      &ty::t[] tag_ty_params) -> ty::t[] {
     let ty::t[] result = ~[];
     auto tpt = ty::lookup_item_type(ccx.tcx, vid);
-    alt (ty::struct(ccx.tcx, tpt._1)) {
+    alt (ty::struct(ccx.tcx, tpt.ty)) {
         case (ty::ty_fn(_, ?ins, _, _, _)) {
 
             // N-ary variant.
@@ -1063,7 +1067,7 @@ mod writeback {
         auto fcx = wbcx.fcx;
         auto tpot = ty::node_id_to_ty_param_substs_opt_and_ty
             (fcx.ccx.tcx, id);
-        auto new_ty = alt (resolve_type_vars_in_type(fcx, sp, tpot._1)) {
+        auto new_ty = alt (resolve_type_vars_in_type(fcx, sp, tpot.ty)) {
             case (some(?t)) { t }
             case (none) {
                 wbcx.success = false;
@@ -1071,7 +1075,7 @@ mod writeback {
             }
         };
         auto new_substs_opt;
-        alt (tpot._0) {
+        alt (tpot.substs) {
             case (none[ty::t[]]) { new_substs_opt = none[ty::t[]]; }
             case (some[ty::t[]](?substs)) {
                 let ty::t[] new_substs = ~[];
@@ -1089,7 +1093,7 @@ mod writeback {
                 new_substs_opt = some[ty::t[]](new_substs);
             }
         }
-        write::ty(fcx.ccx.tcx, id, tup(new_substs_opt, new_ty));
+        write::ty(fcx.ccx.tcx, id, rec(substs=new_substs_opt, ty=new_ty));
     }
 
     type wb_ctxt = rec(@fn_ctxt fcx,
@@ -1291,23 +1295,6 @@ fn gather_locals(&@crate_ctxt ccx, &ast::_fn f,
             next_var_id=*nvi);
 }
 
-
-// AST fragment utilities
-fn replace_expr_type(&@fn_ctxt fcx, &@ast::expr expr,
-                     &tup(ty::t[], ty::t) new_tyt) {
-    auto new_tps;
-    if (ty::expr_has_ty_params(fcx.ccx.tcx, expr)) {
-        new_tps = some[ty::t[]](new_tyt._0);
-    } else { new_tps = none; }
-    write::ty_fixup(fcx, expr.id, tup(new_tps, new_tyt._1));
-}
-
-// FIXME remove once std::ivec::find makes it into a snapshot
-fn ivec_find[T](fn(&T) -> bool  f, &T[] v) -> option::t[T] {
-    for (T elt in v) { if (f(elt)) { ret some[T](elt); } }
-    ret none;
-}
-
 // AST fragment checking
 fn check_lit(@crate_ctxt ccx, &@ast::lit lit) -> ty::t {
     alt (lit.node) {
@@ -1353,7 +1340,7 @@ fn check_pat(&@fn_ctxt fcx, &ast::pat_id_map map, &@ast::pat pat,
             // Typecheck the path.
             auto v_def = lookup_def(fcx, path.span, pat.id);
             auto v_def_ids = ast::variant_def_ids(v_def);
-            auto tag_tpt = ty::lookup_item_type(fcx.ccx.tcx, v_def_ids._0);
+            auto tag_tpt = ty::lookup_item_type(fcx.ccx.tcx, v_def_ids.tg);
             auto path_tpot = instantiate_path(fcx, path, tag_tpt, pat.span);
             // Take the tag type params out of `expected`.
 
@@ -1368,11 +1355,12 @@ fn check_pat(&@fn_ctxt fcx, &ast::pat_id_map map, &@ast::pat pat,
                 auto path_tpt =
                     demand::full(fcx, pat.span, expected, ctor_ty,
                                  expected_tps, NO_AUTODEREF);
-                path_tpot = tup(some[ty::t[]](path_tpt._0), path_tpt._1);
+                path_tpot = rec(substs=some[ty::t[]](path_tpt.substs),
+                                ty=path_tpt.ty);
                 // Get the number of arguments in this tag variant.
 
                 auto arg_types =
-                    variant_arg_types(fcx.ccx, pat.span, v_def_ids._1,
+                    variant_arg_types(fcx.ccx, pat.span, v_def_ids.var,
                                       expected_tps);
                 auto subpats_len = std::ivec::len[@ast::pat](subpats);
                 if (std::ivec::len[ty::t](arg_types) > 0u) {
@@ -1453,7 +1441,7 @@ fn check_pat(&@fn_ctxt fcx, &ast::pat_id_map map, &@ast::pat pat,
                 ret str::eq(name, f.ident);
             }
             for (ast::field_pat f in fields) {
-                alt (ivec_find(bind matches(f.ident, _), ex_fields)) {
+                alt (ivec::find(bind matches(f.ident, _), ex_fields)) {
                     some(?field) {
                         check_pat(fcx, map, f.pat, field.mt.ty);
                     }
@@ -1812,7 +1800,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
                                           "this kind of value does not \
                                            take type parameters");
             }
-            write::ty_only_fixup(fcx, id, tpt._1);
+            write::ty_only_fixup(fcx, id, tpt.ty);
         }
         case (ast::expr_mac(_)) {
             fcx.ccx.tcx.sess.bug("unexpanded macro");
@@ -2027,7 +2015,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
             auto ty_of_arg = bind collect::ty_of_arg(cx, _);
             auto fty =
                 collect::ty_of_fn_decl(cx, convert, ty_of_arg, f.decl,
-                                       f.proto, ~[], none)._1;
+                                       f.proto, ~[], none).ty;
             write::ty_only_fixup(fcx, id, fty);
             check_fn(fcx.ccx, f, id);
         }
@@ -2128,11 +2116,11 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
                                     this_obj_sty =
                                         some(structure_of(fcx,
                                                           expr.span,
-                                                          tpt._1));
+                                                          tpt.ty));
                                 }
                                 case (none) {
                                     fcx.ccx.tcx.sess.bug(
-                                        "didn't find " + int::str(did._1) +
+                                        "didn't find " + int::str(did.node) +
                                         " in type cache");
                                 }
                             }
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index 3fa40c001c3..feba6b006c6 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -26,11 +26,11 @@ fn path_name_i(&ident[] idents) -> str { str::connect_ivec(idents, "::") }
 
 type crate_num = int;
 type node_id = int;
-type def_id = tup(crate_num, node_id);
+type def_id = rec(crate_num crate, node_id node);
 
 const crate_num local_crate = 0;
 fn local_def(node_id id) -> def_id {
-    ret tup(local_crate, id);
+    ret rec(crate=local_crate, node=id);
 }
 
 type ty_param = ident;
@@ -59,9 +59,11 @@ tag def {
     def_upvar(def_id, @def);
 }
 
-fn variant_def_ids(&def d) -> tup(def_id, def_id) {
+fn variant_def_ids(&def d) -> rec(def_id tg, def_id var) {
     alt (d) {
-        case (def_variant(?tag_id, ?var_id)) { ret tup(tag_id, var_id); }
+        case (def_variant(?tag_id, ?var_id)) {
+          ret rec(tg=tag_id, var=var_id);
+        }
     }
 }
 
diff --git a/src/comp/syntax/ext/base.rs b/src/comp/syntax/ext/base.rs
index bdd0421cb23..ac970c64961 100644
--- a/src/comp/syntax/ext/base.rs
+++ b/src/comp/syntax/ext/base.rs
@@ -8,8 +8,9 @@ import codemap;
 
 type syntax_expander =
     fn(&ext_ctxt, span, &(@ast::expr)[], option::t[str]) -> @ast::expr;
+type macro_def = rec(str ident, syntax_extension ext);
 type macro_definer = fn(&ext_ctxt, span, &(@ast::expr)[],
-                        option::t[str]) -> tup(str, syntax_extension);
+                        option::t[str]) -> macro_def;
 
 tag syntax_extension {
     normal(syntax_expander);
diff --git a/src/comp/syntax/ext/expand.rs b/src/comp/syntax/ext/expand.rs
index cb93a4bf45c..3cff1cba5e2 100644
--- a/src/comp/syntax/ext/expand.rs
+++ b/src/comp/syntax/ext/expand.rs
@@ -38,8 +38,8 @@ fn expand_expr(&hashmap[str, base::syntax_extension] exts,
                         case (some(base::macro_defining(?ext))) {
                             auto named_extension
                                 = ext(ext_cx, pth.span, args, body);
-                            exts.insert(named_extension._0,
-                                        named_extension._1);
+                            exts.insert(named_extension.ident,
+                                        named_extension.ext);
                             ast::expr_tup(~[])
                         }
                     }
diff --git a/src/comp/syntax/ext/fmt.rs b/src/comp/syntax/ext/fmt.rs
index 4aae16f01ce..b69b27f5ef4 100644
--- a/src/comp/syntax/ext/fmt.rs
+++ b/src/comp/syntax/ext/fmt.rs
@@ -80,11 +80,12 @@ fn pieces_to_expr(&ext_ctxt cx, span sp, vec[piece] pieces,
         ret @rec(id=cx.next_id(), node=callexpr, span=sp);
     }
     fn make_rec_expr(&ext_ctxt cx, span sp,
-                     vec[tup(ast::ident, @ast::expr)] fields) -> @ast::expr {
+                     vec[rec(ast::ident ident, @ast::expr ex)] fields)
+        -> @ast::expr {
         let ast::field[] astfields = ~[];
-        for (tup(ast::ident, @ast::expr) field in fields) {
-            auto ident = field._0;
-            auto val = field._1;
+        for (rec(ast::ident ident, @ast::expr ex) field in fields) {
+            auto ident = field.ident;
+            auto val = field.ex;
             auto astfield =
                 rec(node=rec(mut=ast::imm, ident=ident, expr=val), span=sp);
             astfields += ~[astfield];
@@ -173,10 +174,10 @@ fn pieces_to_expr(&ext_ctxt cx, span sp, vec[piece] pieces,
                          @ast::expr width_expr, @ast::expr precision_expr,
                          @ast::expr ty_expr) -> @ast::expr {
             ret make_rec_expr(cx, sp,
-                              [tup("flags", flags_expr),
-                               tup("width", width_expr),
-                               tup("precision", precision_expr),
-                               tup("ty", ty_expr)]);
+                              [rec(ident="flags", ex=flags_expr),
+                               rec(ident="width", ex=width_expr),
+                               rec(ident="precision", ex=precision_expr),
+                               rec(ident="ty", ex=ty_expr)]);
         }
         auto rt_conv_flags = make_flags(cx, sp, cnv.flags);
         auto rt_conv_width = make_count(cx, sp, cnv.width);
diff --git a/src/comp/syntax/ext/simplext.rs b/src/comp/syntax/ext/simplext.rs
index 839cf154d75..95cbb069c25 100644
--- a/src/comp/syntax/ext/simplext.rs
+++ b/src/comp/syntax/ext/simplext.rs
@@ -191,10 +191,11 @@ selectors. */
 fn use_selectors_to_bind(&binders b, @expr e) -> option::t[bindings] {
     auto res = new_str_hash[arb_depth[matchable]]();
     let bool never_mind = false;
-    for each(@tup(ident, selector) pair in b.real_binders.items()) {
-        alt (pair._1(match_expr(e))) {
+    for each(@rec(ident key, selector val) pair
+             in b.real_binders.items()) {
+        alt (pair.val(match_expr(e))) {
           case (none) { never_mind = true; }
-          case (some(?mtc)) { res.insert(pair._0, mtc); }
+          case (some(?mtc)) { res.insert(pair.key, mtc); }
         }
     }
     if (never_mind) { ret none; } //HACK: `ret` doesn't work in `for each`
@@ -274,9 +275,7 @@ iter free_vars(&bindings b, @expr e) -> ident {
     auto f = make_fold(f_pre);
     f.fold_expr(e); // ignore result
     dummy_out(f);
-    for each(@tup(ast::ident, ()) it in idents.items()) {
-        put it._0;
-    }
+    for each(ident id in idents.keys()) { put id; }
 }
 
 
@@ -546,7 +545,7 @@ fn p_t_s_r_actual_vector(&ext_ctxt cx, (@expr)[] elts, &selector s,
 }
 
 fn add_new_extension(&ext_ctxt cx, span sp, &(@expr)[] args,
-                     option::t[str] body) -> tup(str, syntax_extension) {
+                     option::t[str] body) -> base::macro_def {
     let option::t[str] macro_name = none;
     let (clause)[] clauses = ~[];
     for (@expr arg in args) {
@@ -596,14 +595,13 @@ fn add_new_extension(&ext_ctxt cx, span sp, &(@expr)[] args,
 
     auto ext = bind generic_extension(_,_,_,_,clauses);
 
-    ret tup(alt (macro_name) {
+    ret rec(ident=alt (macro_name) {
       case (some(?id)) { id }
       case (none) {
         cx.span_fatal(sp, "macro definition must have "
                       + "at least one clause")
       }
-    },
-            normal(ext));
+    }, ext=normal(ext));
 
 
     fn generic_extension(&ext_ctxt cx, span sp, &(@expr)[] args,
@@ -620,9 +618,9 @@ fn add_new_extension(&ext_ctxt cx, span sp, &(@expr)[] args,
                 alt (use_selectors_to_bind(c.params.(i), args.(i))) {
                   case (some(?new_bindings)) {
                     /* ick; I wish macros just took one expr */
-                    for each (@tup(ident,arb_depth[matchable]) it
+                    for each (@rec(ident key, arb_depth[matchable] val) it
                               in new_bindings.items()) {
-                        bdgs.insert(it._0, it._1);
+                        bdgs.insert(it.key, it.val);
                     }
                   }
                   case (none) { abort = true; }
diff --git a/src/comp/syntax/parse/eval.rs b/src/comp/syntax/parse/eval.rs
index 45bc78cdc61..6f551b92943 100644
--- a/src/comp/syntax/parse/eval.rs
+++ b/src/comp/syntax/parse/eval.rs
@@ -60,8 +60,8 @@ fn eval_crate_directive(ctx cx, @ast::crate_directive cdir, str prefix,
                 new_parser_from_file(cx.sess, cx.cfg, full_path, cx.chpos,
                                      cx.byte_pos);
             auto inner_attrs = parse_inner_attrs_and_next(p0);
-            auto mod_attrs = attrs + inner_attrs._0;
-            auto first_item_outer_attrs = inner_attrs._1;
+            auto mod_attrs = attrs + inner_attrs.inner;
+            auto first_item_outer_attrs = inner_attrs.next;
             auto m0 = parse_mod_items(p0, token::EOF, first_item_outer_attrs);
 
             auto i = syntax::parse::parser::mk_item
diff --git a/src/comp/syntax/parse/lexer.rs b/src/comp/syntax/parse/lexer.rs
index cdbc6bafec9..07a07923275 100644
--- a/src/comp/syntax/parse/lexer.rs
+++ b/src/comp/syntax/parse/lexer.rs
@@ -57,8 +57,8 @@ fn new_reader(&codemap::codemap cm, str src, codemap::filemap filemap,
         fn init() {
             if (pos < len) {
                 auto next = str::char_range_at(src, pos);
-                pos = next._1;
-                ch = next._0;
+                pos = next.next;
+                ch = next.ch;
             }
         }
         fn bump() {
@@ -70,8 +70,8 @@ fn new_reader(&codemap::codemap cm, str src, codemap::filemap filemap,
                     col = 0u;
                 }
                 auto next = str::char_range_at(src, pos);
-                pos = next._1;
-                ch = next._0;
+                pos = next.next;
+                ch = next.ch;
             } else { ch = -1 as char; }
         }
         fn get_interner() -> @interner::interner[str] { ret itr; }
@@ -338,13 +338,13 @@ fn scan_numeric_escape(&reader rdr, uint n_hex_digits) -> char {
     ret accum_int as char;
 }
 
-fn next_token(&reader rdr) -> tup(token::token, uint, uint) {
+fn next_token(&reader rdr) -> rec(token::token tok, uint chpos, uint bpos) {
     consume_whitespace_and_comments(rdr);
     auto start_chpos = rdr.get_chpos();
     auto start_bpos = rdr.get_byte_pos();
     auto tok = if rdr.is_eof() { token::EOF }
                else { next_token_inner(rdr) };
-    ret tup(tok, start_chpos, start_bpos);
+    ret rec(tok=tok, chpos=start_chpos, bpos=start_bpos);
 }
 
 fn next_token_inner(&reader rdr) -> token::token {
@@ -768,10 +768,10 @@ fn gather_comments_and_literals(&codemap::codemap cm, str path,
             break;
         }
         auto tok = next_token(rdr);
-        if (is_lit(tok._0)) {
-            literals += ~[rec(lit=rdr.get_str_from(tok._2), pos=tok._1)];
+        if (is_lit(tok.tok)) {
+            literals += ~[rec(lit=rdr.get_str_from(tok.bpos), pos=tok.chpos)];
         }
-        log "tok: " + token::to_str(rdr, tok._0);
+        log "tok: " + token::to_str(rdr, tok.tok);
         first_read = false;
     }
     ret rec(cmnts=comments, lits=literals);
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index e4bb9c6e1e3..43f8a62b23d 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -81,7 +81,7 @@ fn new_parser(parse_sess sess, ast::crate_cfg cfg, lexer::reader rdr,
                      mutable token::token tok,
                      mutable span tok_span,
                      mutable span last_tok_span,
-                     mutable tup(token::token, span)[] buffer,
+                     mutable rec(token::token tok, span span)[] buffer,
                      mutable restriction restr,
                      lexer::reader rdr,
                      @op_spec[] precs,
@@ -91,21 +91,21 @@ fn new_parser(parse_sess sess, ast::crate_cfg cfg, lexer::reader rdr,
             last_tok_span = tok_span;
             if ivec::len(buffer) == 0u {
                 auto next = lexer::next_token(rdr);
-                tok = next._0;
-                tok_span = rec(lo=next._1, hi=rdr.get_chpos());
+                tok = next.tok;
+                tok_span = rec(lo=next.chpos, hi=rdr.get_chpos());
             } else {
                 auto next = ivec::pop(buffer);
-                tok = next._0;
-                tok_span = next._1;
+                tok = next.tok;
+                tok_span = next.span;
             }
         }
         fn look_ahead(uint distance) -> token::token {
             while ivec::len(buffer) < distance {
                 auto next = lexer::next_token(rdr);
-                auto sp = rec(lo=next._1, hi=rdr.get_chpos());
-                buffer = ~[tup(next._0, sp)] + buffer;
+                auto sp = rec(lo=next.chpos, hi=rdr.get_chpos());
+                buffer = ~[rec(tok=next.tok, span=sp)] + buffer;
             }
-            ret buffer.(distance-1u)._0;
+            ret buffer.(distance-1u).tok;
         }
         fn fatal(str m) -> ! {
             codemap::emit_error(some(self.get_span()), m, sess.cm);
@@ -137,8 +137,8 @@ fn new_parser(parse_sess sess, ast::crate_cfg cfg, lexer::reader rdr,
     }
 
     auto tok0 = lexer::next_token(rdr);
-    auto span0 = rec(lo=tok0._1, hi=rdr.get_chpos());
-    ret stdio_parser(sess, cfg, ftype, tok0._0,
+    auto span0 = rec(lo=tok0.chpos, hi=rdr.get_chpos());
+    ret stdio_parser(sess, cfg, ftype, tok0.tok,
                      span0, span0, ~[], UNRESTRICTED, rdr,
                      prec_table(), bad_expr_word_table());
 }
@@ -1307,9 +1307,10 @@ fn parse_assign_expr(&parser p) -> @ast::expr {
     ret lhs;
 }
 
-fn parse_if_expr_1(&parser p) -> tup(@ast::expr,
-                                     ast::blk, option::t[@ast::expr],
-                                     uint, uint) {
+fn parse_if_expr_1(&parser p) -> rec(@ast::expr cond,
+                                     ast::blk then,
+                                     option::t[@ast::expr] els,
+                                     uint lo, uint hi) {
     auto lo = p.get_last_lo_pos();
     auto cond = parse_expr(p);
     auto thn = parse_block(p);
@@ -1320,17 +1321,18 @@ fn parse_if_expr_1(&parser p) -> tup(@ast::expr,
         els = some(elexpr);
         hi = elexpr.span.hi;
     }
-    ret tup(cond, thn, els, lo, hi);
+    ret rec(cond=cond, then=thn, els=els, lo=lo, hi=hi);
 }
 
 fn parse_if_expr(&parser p) -> @ast::expr {
     if (eat_word(p, "check")) {
             auto q = parse_if_expr_1(p);
-            ret mk_expr(p, q._3, q._4, ast::expr_if_check(q._0, q._1, q._2));
+            ret mk_expr(p, q.lo, q.hi,
+                        ast::expr_if_check(q.cond, q.then, q.els));
     }
     else {
         auto q = parse_if_expr_1(p);
-        ret mk_expr(p, q._3, q._4, ast::expr_if(q._0, q._1, q._2));
+        ret mk_expr(p, q.lo, q.hi, ast::expr_if(q.cond, q.then, q.els));
     }
 }
 
@@ -1894,10 +1896,10 @@ fn parse_fn(&parser p, ast::proto proto, ast::purity purity) -> ast::_fn {
     ret rec(decl=decl, proto=proto, body=body);
 }
 
-fn parse_fn_header(&parser p) -> tup(ast::ident, ast::ty_param[]) {
+fn parse_fn_header(&parser p) -> rec(ast::ident ident, ast::ty_param[] tps) {
     auto id = parse_value_ident(p);
     auto ty_params = parse_ty_params(p);
-    ret tup(id, ty_params);
+    ret rec(ident=id, tps=ty_params);
 }
 
 fn mk_item(&parser p, uint lo, uint hi, &ast::ident ident, &ast::item_ node,
@@ -1914,7 +1916,8 @@ fn parse_item_fn_or_iter(&parser p, ast::purity purity, ast::proto proto,
     auto lo = p.get_last_lo_pos();
     auto t = parse_fn_header(p);
     auto f = parse_fn(p, proto, purity);
-    ret mk_item(p, lo, f.body.span.hi, t._0, ast::item_fn(f, t._1), attrs);
+    ret mk_item(p, lo, f.body.span.hi, t.ident,
+                ast::item_fn(f, t.tps), attrs);
 }
 
 fn parse_obj_field(&parser p) -> ast::obj_field {
@@ -2045,11 +2048,11 @@ fn parse_item_mod(&parser p, &ast::attribute[] attrs) -> @ast::item {
     auto id = parse_ident(p);
     expect(p, token::LBRACE);
     auto inner_attrs = parse_inner_attrs_and_next(p);
-    auto first_item_outer_attrs = inner_attrs._1;
+    auto first_item_outer_attrs = inner_attrs.next;
     auto m = parse_mod_items(p, token::RBRACE, first_item_outer_attrs);
     auto hi = p.get_hi_pos();
     expect(p, token::RBRACE);
-    ret mk_item(p, lo, hi, id, ast::item_mod(m), attrs + inner_attrs._0);
+    ret mk_item(p, lo, hi, id, ast::item_mod(m), attrs + inner_attrs.inner);
 }
 
 fn parse_item_native_type(&parser p, &ast::attribute[] attrs)
@@ -2057,11 +2060,11 @@ fn parse_item_native_type(&parser p, &ast::attribute[] attrs)
     auto t = parse_type_decl(p);
     auto hi = p.get_hi_pos();
     expect(p, token::SEMI);
-    ret @rec(ident=t._1,
+    ret @rec(ident=t.ident,
              attrs=attrs,
              node=ast::native_item_ty,
              id=p.get_id(),
-             span=rec(lo=t._0, hi=hi));
+             span=rec(lo=t.lo, hi=hi));
 }
 
 fn parse_item_native_fn(&parser p, &ast::attribute[] attrs)
@@ -2076,9 +2079,9 @@ fn parse_item_native_fn(&parser p, &ast::attribute[] attrs)
     }
     auto hi = p.get_hi_pos();
     expect(p, token::SEMI);
-    ret @rec(ident=t._0,
+    ret @rec(ident=t.ident,
              attrs=attrs,
-             node=ast::native_item_fn(link_name, decl, t._1),
+             node=ast::native_item_fn(link_name, decl, t.tps),
              id=p.get_id(),
              span=rec(lo=lo, hi=hi));
 }
@@ -2142,8 +2145,8 @@ fn parse_item_native_mod(&parser p, &ast::attribute[] attrs) -> @ast::item {
     }
     expect(p, token::LBRACE);
     auto more_attrs = parse_inner_attrs_and_next(p);
-    auto inner_attrs = more_attrs._0;
-    auto first_item_outer_attrs = more_attrs._1;
+    auto inner_attrs = more_attrs.inner;
+    auto first_item_outer_attrs = more_attrs.next;
     auto m = parse_native_mod_items(p, native_name, abi,
                                     first_item_outer_attrs);
     auto hi = p.get_hi_pos();
@@ -2151,10 +2154,10 @@ fn parse_item_native_mod(&parser p, &ast::attribute[] attrs) -> @ast::item {
     ret mk_item(p, lo, hi, id, ast::item_native_mod(m), attrs + inner_attrs);
 }
 
-fn parse_type_decl(&parser p) -> tup(uint, ast::ident) {
+fn parse_type_decl(&parser p) -> rec(uint lo, ast::ident ident) {
     auto lo = p.get_last_lo_pos();
     auto id = parse_ident(p);
-    ret tup(lo, id);
+    ret rec(lo=lo, ident=id);
 }
 
 fn parse_item_type(&parser p, &ast::attribute[] attrs) -> @ast::item {
@@ -2164,7 +2167,7 @@ fn parse_item_type(&parser p, &ast::attribute[] attrs) -> @ast::item {
     auto ty = parse_ty(p);
     auto hi = p.get_hi_pos();
     expect(p, token::SEMI);
-    ret mk_item(p, t._0, hi, t._1, ast::item_ty(ty, tps), attrs);
+    ret mk_item(p, t.lo, hi, t.ident, ast::item_ty(ty, tps), attrs);
 }
 
 fn parse_item_tag(&parser p, &ast::attribute[] attrs) -> @ast::item {
@@ -2330,8 +2333,8 @@ fn parse_attribute_naked(&parser p, ast::attr_style style,
 // next item (since we can't know whether the attribute is an inner attribute
 // of the containing item or an outer attribute of the first contained item
 // until we see the semi).
-fn parse_inner_attrs_and_next(&parser p) -> tup(ast::attribute[],
-                                                ast::attribute[]) {
+fn parse_inner_attrs_and_next(&parser p) -> rec(ast::attribute[] inner,
+                                                ast::attribute[] next) {
     let ast::attribute[] inner_attrs = ~[];
     let ast::attribute[] next_outer_attrs = ~[];
     while (p.peek() == token::POUND) {
@@ -2349,7 +2352,7 @@ fn parse_inner_attrs_and_next(&parser p) -> tup(ast::attribute[],
             break;
         }
     }
-    ret tup(inner_attrs, next_outer_attrs);
+    ret rec(inner=inner_attrs, next=next_outer_attrs);
 }
 
 fn parse_meta_item(&parser p) -> @ast::meta_item {
@@ -2527,12 +2530,12 @@ fn parse_crate_mod(&parser p, &ast::crate_cfg cfg, parse_sess sess)
     -> @ast::crate {
     auto lo = p.get_lo_pos();
     auto crate_attrs = parse_inner_attrs_and_next(p);
-    auto first_item_outer_attrs = crate_attrs._1;
+    auto first_item_outer_attrs = crate_attrs.next;
     auto m = parse_mod_items(p, token::EOF,
                              first_item_outer_attrs);
     ret @spanned(lo, p.get_lo_pos(), rec(directives=~[],
                                          module=m,
-                                         attrs=crate_attrs._0,
+                                         attrs=crate_attrs.inner,
                                          config=p.get_cfg()));
 }
 
@@ -2585,8 +2588,8 @@ fn parse_crate_directive(&parser p, &ast::attribute[] first_outer_attr)
                  token::LBRACE) {
                 p.bump();
                 auto inner_attrs = parse_inner_attrs_and_next(p);
-                auto mod_attrs = outer_attrs + inner_attrs._0;
-                auto next_outer_attr = inner_attrs._1;
+                auto mod_attrs = outer_attrs + inner_attrs.inner;
+                auto next_outer_attr = inner_attrs.next;
                 auto cdirs = parse_crate_directives(p, token::RBRACE,
                                                     next_outer_attr);
                 auto hi = p.get_hi_pos();
@@ -2636,8 +2639,8 @@ fn parse_crate_from_crate_file(&str input, &ast::crate_cfg cfg,
     auto lo = p.get_lo_pos();
     auto prefix = std::fs::dirname(p.get_filemap().name);
     auto leading_attrs = parse_inner_attrs_and_next(p);
-    auto crate_attrs = leading_attrs._0;
-    auto first_cdir_attr = leading_attrs._1;
+    auto crate_attrs = leading_attrs.inner;
+    auto first_cdir_attr = leading_attrs.next;
     auto cdirs = parse_crate_directives(p, token::EOF, first_cdir_attr);
     let str[] deps = ~[];
     auto cx = @rec(p=p,
diff --git a/src/comp/util/common.rs b/src/comp/util/common.rs
index a6b980a79a1..3ffef690334 100644
--- a/src/comp/util/common.rs
+++ b/src/comp/util/common.rs
@@ -31,13 +31,13 @@ import print::pp::mk_printer;
 type flag = hashmap[str, ()];
 
 fn def_eq(&ast::def_id a, &ast::def_id b) -> bool {
-    ret a._0 == b._0 && a._1 == b._1;
+    ret a.crate == b.crate && a.node == b.node;
 }
 
 fn hash_def(&ast::def_id d) -> uint {
     auto h = 5381u;
-    h = (h << 5u) + h ^ (d._0 as uint);
-    h = (h << 5u) + h ^ (d._1 as uint);
+    h = (h << 5u) + h ^ (d.crate as uint);
+    h = (h << 5u) + h ^ (d.node as uint);
     ret h;
 }
 
diff --git a/src/comp/util/ppaux.rs b/src/comp/util/ppaux.rs
index 305ef84b85a..41209a11602 100644
--- a/src/comp/util/ppaux.rs
+++ b/src/comp/util/ppaux.rs
@@ -116,7 +116,7 @@ fn ty_to_str(&ctxt cx, &t typ) -> str {
         case (ty_tag(?id, ?tps)) {
             // The user should never see this if the cname is set properly!
 
-            s += "<tag#" + int::str(id._0) + ":" + int::str(id._1) + ">";
+            s += "<tag#" + int::str(id.crate) + ":" + int::str(id.node) + ">";
             if (ivec::len[t](tps) > 0u) {
                 let str[] strs = ~[];
                 for (t typ in tps) { strs += ~[ty_to_str(cx, typ)]; }
@@ -136,7 +136,8 @@ fn ty_to_str(&ctxt cx, &t typ) -> str {
             s += "obj {\n\t" + str::connect_ivec(strs, "\n\t") + "\n}";
         }
         case (ty_res(?id, _, _)) {
-            s += "<resource#" + int::str(id._0) + ":" + int::str(id._1) + ">";
+            s += "<resource#" + int::str(id.node) + ":" +
+                int::str(id.crate) + ">";
         }
         case (ty_var(?v)) { s += "<T" + int::str(v) + ">"; }
         case (ty_param(?id)) {