about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-06-24 18:10:40 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-06-25 21:15:11 +0200
commit61fc12d0d0d1b8acb7472bfc6223882b32acd3d2 (patch)
treef608c6036509602785bf35a7f879bf15560d4d1b
parent781a265b88f7fc3c8c406b327e8a548e742d6224 (diff)
downloadrust-61fc12d0d0d1b8acb7472bfc6223882b32acd3d2.tar.gz
rust-61fc12d0d0d1b8acb7472bfc6223882b32acd3d2.zip
Partial implementation of resources
Non-copyability is not enforced yet, and something is still flaky with
dropping of the internal value, so don't actually use them yet. I'm
merging this in so that I don't have to keep merging against new
patches.
-rw-r--r--src/comp/front/ast.rs6
-rw-r--r--src/comp/front/creader.rs5
-rw-r--r--src/comp/front/parser.rs28
-rw-r--r--src/comp/middle/metadata.rs35
-rw-r--r--src/comp/middle/resolve.rs15
-rw-r--r--src/comp/middle/trans.rs50
-rw-r--r--src/comp/middle/tstate/pre_post_conditions.rs9
-rw-r--r--src/comp/middle/ty.rs24
-rw-r--r--src/comp/middle/typeck.rs25
-rw-r--r--src/comp/middle/visit.rs3
-rw-r--r--src/comp/middle/walk.rs3
-rw-r--r--src/comp/pretty/pprust.rs12
12 files changed, 198 insertions, 17 deletions
diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs
index 1778014da01..bfe7d576cfd 100644
--- a/src/comp/front/ast.rs
+++ b/src/comp/front/ast.rs
@@ -335,7 +335,7 @@ tag ty_ {
      /* bot represents the value of functions that don't return a value
         locally to their context. in contrast, things like log that do
         return, but don't return a meaningful value, have result type nil. */
-     ty_bool;
+    ty_bool;
     ty_int;
     ty_uint;
     ty_float;
@@ -478,7 +478,7 @@ type attribute_ = rec(attr_style style, meta_item value);
 
 type item = rec(ident ident,
                 vec[attribute] attrs,
-                node_id id, // For objs, this is the type's def_id
+                node_id id, // For objs and resources, this is the type def_id
                 item_ node,
                 span span);
 
@@ -490,6 +490,8 @@ tag item_ {
     item_ty(@ty, vec[ty_param]);
     item_tag(vec[variant], vec[ty_param]);
     item_obj(_obj, vec[ty_param], node_id /* constructor id */);
+    item_res(_fn /* dtor */, node_id /* dtor id */,
+             vec[ty_param], node_id /* ctor id */);
 }
 
 type native_item = rec(ident ident,
diff --git a/src/comp/front/creader.rs b/src/comp/front/creader.rs
index 27623422e5d..e6e48c78df7 100644
--- a/src/comp/front/creader.rs
+++ b/src/comp/front/creader.rs
@@ -281,6 +281,11 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
             st.pos += 1u;
             ret ty::mk_obj(st.tcx, methods);
         }
+        case ('r') {
+            auto def = parse_def(st, sd);
+            auto inner = parse_ty(st, sd);
+            ret ty::mk_res(st.tcx, def, inner);
+        }
         case ('X') { ret ty::mk_var(st.tcx, parse_int(st)); }
         case ('E') { ret ty::mk_native(st.tcx); }
         case ('Y') { ret ty::mk_type(st.tcx); }
diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs
index 45f9424d641..a39b6885583 100644
--- a/src/comp/front/parser.rs
+++ b/src/comp/front/parser.rs
@@ -139,6 +139,7 @@ fn bad_expr_word_table() -> hashmap[str, ()] {
     words.insert("be", ());
     words.insert("fail", ());
     words.insert("type", ());
+    words.insert("res", ());
     words.insert("check", ());
     words.insert("assert", ());
     words.insert("claim", ());
@@ -1656,7 +1657,6 @@ fn parse_ty_params(&parser p) -> vec[ast::ty_param] {
 }
 
 fn parse_fn_decl(&parser p, ast::purity purity) -> ast::fn_decl {
-    auto pf = parse_arg;
     let util::common::spanned[vec[ast::arg]] inputs =
         parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_arg,
                   p);
@@ -1765,10 +1765,9 @@ fn parse_item_obj(&parser p, ast::layer lyr, vec[ast::attribute] attrs) ->
     auto lo = p.get_last_lo_pos();
     auto ident = parse_value_ident(p);
     auto ty_params = parse_ty_params(p);
-    auto pf = parse_obj_field;
     let util::common::spanned[vec[ast::obj_field]] fields =
         parse_seq[ast::obj_field](token::LPAREN, token::RPAREN,
-                                  some(token::COMMA), pf, p);
+                                  some(token::COMMA), parse_obj_field, p);
     let vec[@ast::method] meths = [];
     let option::t[@ast::method] dtor = none;
     expect(p, token::LBRACE);
@@ -1784,6 +1783,27 @@ fn parse_item_obj(&parser p, ast::layer lyr, vec[ast::attribute] attrs) ->
                                                 p.get_id()), attrs);
 }
 
+fn parse_item_res(&parser p, ast::layer lyr, vec[ast::attribute] attrs) ->
+   @ast::item {
+    auto lo = p.get_last_lo_pos();
+    auto ident = parse_value_ident(p);
+    auto ty_params = parse_ty_params(p);
+    expect(p, token::LPAREN);
+    auto t = parse_ty(p);
+    auto arg_ident = parse_value_ident(p);
+    expect(p, token::RPAREN);
+    auto dtor = parse_block(p);
+    auto decl = rec(inputs=[rec(mode=ast::alias(false), ty=t, ident=arg_ident,
+                                id=p.get_id())],
+                    output=@spanned(lo, lo, ast::ty_nil),
+                    purity=ast::impure_fn,
+                    cf=ast::return,
+                    constraints=[]);
+    auto f = rec(decl=decl, proto=ast::proto_fn, body=dtor);
+    ret mk_item(p, lo, dtor.span.hi, ident,
+                ast::item_res(f, p.get_id(), ty_params, p.get_id()), attrs);
+}
+
 fn parse_mod_items(&parser p, token::token term,
                    vec[ast::attribute] first_item_attrs) -> ast::_mod {
     auto view_items = if (vec::len(first_item_attrs) == 0u) {
@@ -2028,6 +2048,8 @@ fn parse_item(&parser p, vec[ast::attribute] attrs) -> parsed_item {
         ret got_item(parse_item_tag(p, attrs));
     } else if (eat_word(p, "obj")) {
         ret got_item(parse_item_obj(p, lyr, attrs));
+    } else if (eat_word(p, "res")) {
+        ret got_item(parse_item_res(p, lyr, attrs));
     } else { ret no_item; }
 }
 
diff --git a/src/comp/middle/metadata.rs b/src/comp/middle/metadata.rs
index b9f4ed5c2fb..ae59a208fa3 100644
--- a/src/comp/middle/metadata.rs
+++ b/src/comp/middle/metadata.rs
@@ -231,6 +231,12 @@ mod encode {
                 }
                 w.write_char(']');
             }
+            case (ty::ty_res(?def, ?ty)) {
+                w.write_char('r');
+                w.write_str(cx.ds(def));
+                w.write_char('|');
+                enc_ty(w, cx, ty);
+            }
             case (ty::ty_var(?id)) {
                 w.write_char('X');
                 w.write_str(common::istr(id));
@@ -393,6 +399,18 @@ fn encode_module_item_paths(&ebml::writer ebml_w, &_mod module,
                 encode_def_id(ebml_w, local_def(it.id));
                 ebml::end_tag(ebml_w);
             }
+            case (item_res(_, _, ?tps, ?ctor_id)) {
+                add_to_index(ebml_w, path, index, it.ident);
+                ebml::start_tag(ebml_w, tag_paths_data_item);
+                encode_name(ebml_w, it.ident);
+                encode_def_id(ebml_w, local_def(ctor_id));
+                ebml::end_tag(ebml_w);
+                add_to_index(ebml_w, path, index, it.ident);
+                ebml::start_tag(ebml_w, tag_paths_data_item);
+                encode_name(ebml_w, it.ident);
+                encode_def_id(ebml_w, local_def(it.id));
+                ebml::end_tag(ebml_w);
+            }
             case (item_tag(?variants, ?tps)) {
                 add_to_index(ebml_w, path, index, it.ident);
                 ebml::start_tag(ebml_w, tag_paths_data_item);
@@ -553,6 +571,23 @@ fn encode_info_for_item(@trans::crate_ctxt cx, &ebml::writer ebml_w,
             encode_tag_variant_info(cx, ebml_w, item.id, variants, index,
                                     tps);
         }
+        case (item_res(_, _, ?tps, ?ctor_id)) {
+            ebml::start_tag(ebml_w, tag_items_data_item);
+            encode_def_id(ebml_w, local_def(ctor_id));
+            encode_kind(ebml_w, 'f' as u8);
+            encode_type_param_count(ebml_w, tps);
+            auto fn_ty = trans::node_id_type(cx, item.id);
+            encode_type(cx, ebml_w, fn_ty);
+            encode_symbol(cx, ebml_w, ctor_id);
+            ebml::end_tag(ebml_w);
+            index += [tup(item.id, ebml_w.writer.tell())];
+            ebml::start_tag(ebml_w, tag_items_data_item);
+            encode_def_id(ebml_w, local_def(item.id));
+            encode_kind(ebml_w, 'y' as u8);
+            encode_type_param_count(ebml_w, tps);
+            encode_type(cx, ebml_w, ty::ty_fn_ret(cx.tcx, fn_ty));
+            ebml::end_tag(ebml_w);
+        }
         case (item_obj(_, ?tps, ?ctor_id)) {
             ebml::start_tag(ebml_w, tag_items_data_item);
             encode_def_id(ebml_w, local_def(ctor_id));
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 3ecb81267c1..b9f6c604996 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -819,6 +819,14 @@ fn found_def_item(&@ast::item i, namespace ns) -> option::t[def] {
                 ret some(ast::def_ty(local_def(i.id)));
             }
         }
+        case (ast::item_res(_, _, _, ?ctor_id)) {
+            alt (ns) {
+                case (ns_value) { ret some(ast::def_fn(local_def(ctor_id),
+                                                       ast::impure_fn)); }
+                case (ns_type) { ret some(ast::def_ty(local_def(i.id))); }
+                case (_) { }
+            }
+        }
         case (ast::item_tag(_, _)) {
             if (ns == ns_type) {
                 ret some(ast::def_ty(local_def(i.id)));
@@ -1085,6 +1093,9 @@ fn index_mod(&ast::_mod md) -> mod_index {
             case (ast::item_ty(_, _)) {
                 add_to_index(index, it.ident, mie_item(it));
             }
+            case (ast::item_res(_, _, _, _)) {
+                add_to_index(index, it.ident, mie_item(it));
+            }
             case (ast::item_tag(?variants, _)) {
                 add_to_index(index, it.ident, mie_item(it));
                 let uint variant_idx = 0u;
@@ -1282,6 +1293,10 @@ fn check_block(@env e, &ast::block b, &() x, &vt[()] v) {
                             case (ast::item_ty(_, _)) {
                                 add_name(types, it.span, it.ident);
                             }
+                            case (ast::item_res(_, _, _, _)) {
+                                add_name(types, it.span, it.ident);
+                                add_name(values, it.span, it.ident);
+                            }
                             case (ast::item_obj(_, _, _)) {
                                 add_name(types, it.span, it.ident);
                                 add_name(values, it.span, it.ident);
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 59f7dd84073..3a67296e86d 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -881,6 +881,9 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
             abs_pair = llvm::LLVMResolveTypeHandle(th.llth);
             llty = abs_pair;
         }
+        case (ty::ty_res(_, ?sub)) {
+            ret type_of_inner(cx, sp, sub);
+        }
         case (ty::ty_var(_)) {
             cx.tcx.sess.span_fatal(sp, "trans::type_of called on ty_var");
         }
@@ -1217,6 +1220,7 @@ fn simplify_type(&@crate_ctxt ccx, &ty::t typ) -> ty::t {
                                     ty::mk_imm_box(ccx.tcx,
                                                    ty::mk_nil(ccx.tcx))]);
             }
+            case (ty::ty_res(_, ?sub)) { ret simplify_type(ccx, sub);}
             case (_) { ret typ; }
         }
     }
@@ -2064,7 +2068,7 @@ fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
         case (ty::ty_vec(_)) { decr_refcnt_maybe_free(cx, v0, v0, t) }
         case (ty::ty_ivec(?tm)) {
             auto v1;
-            if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tm.ty)) {
+            if (ty::type_has_dynamic_size(ccx.tcx, tm.ty)) {
                 v1 = cx.build.PointerCast(v0, T_ptr(T_opaque_ivec()));
             } else {
                 v1 = v0;
@@ -2082,6 +2086,18 @@ fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
                 cx.build.GEP(v0, [C_int(0), C_int(abi::obj_field_box)]);
             decr_refcnt_maybe_free(cx, box_cell, v0, t)
         }
+        case (ty::ty_res(?did, ?inner)) {
+            auto dtor = alt (ccx.ast_map.get(did._1)) {
+                case (ast_map::node_item(?i)) {
+                    alt (i.node) {
+                        case (ast::item_res(?dtor, _, _, _)) { dtor }
+                    }
+                }
+            };
+            cx.fcx.llargs.insert(dtor.decl.inputs.(0).id, v0);
+            auto rs = trans_block(cx, dtor.body, return);
+            drop_ty(rs.bcx, v0, inner)
+        }
         case (ty::ty_fn(_, _, _, _, _)) {
             auto box_cell =
                 cx.build.GEP(v0, [C_int(0), C_int(abi::fn_field_box)]);
@@ -2549,6 +2565,10 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv,
                 i += 1;
             }
         }
+        case (ty::ty_res(_, ?inner)) {
+            f(r.bcx, load_if_immediate(r.bcx, av, inner),
+              load_if_immediate(r.bcx, bv, inner), inner);
+        }
         case (ty::ty_tag(?tid, ?tps)) {
             auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, tid);
             auto n_variants = vec::len[ty::variant_info](variants);
@@ -4633,12 +4653,10 @@ fn lval_generic_fn(&@block_ctxt cx, &ty::ty_param_count_and_ty tpt,
     auto lv;
     if (cx.fcx.lcx.ccx.sess.get_targ_crate_num() == fn_id._0) {
         // 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));
     } else {
         // External reference.
-
         lv = trans_external_path(cx, fn_id, tpt);
     }
     auto tys = ty::node_id_to_type_params(cx.fcx.lcx.ccx.tcx, id);
@@ -7621,6 +7639,26 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::node_id ctor_id,
     finish_fn(fcx, lltop);
 }
 
+fn trans_res(@local_ctxt cx, &span sp, &ast::_fn f, ast::node_id ctor_id,
+             &vec[ast::ty_param] ty_params) {
+    auto llctor_decl = cx.ccx.item_ids.get(ctor_id);
+    auto fcx = new_fn_ctxt(cx, sp, llctor_decl);
+    auto ret_ty = ty::ret_ty_of_fn(cx.ccx.tcx, ctor_id);
+    create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair],
+                              ret_ty, f.decl.inputs, ty_params);
+    auto bcx = new_top_block_ctxt(fcx);
+    auto lltop = bcx.llbb;
+    auto self_ty = ty::ret_ty_of_fn(cx.ccx.tcx, ctor_id);
+    auto llself_ty = type_of(cx.ccx, sp, self_ty);
+    auto arg_ty = arg_tys_of_fn(cx.ccx, ctor_id).(0).ty;
+    auto arg = load_if_immediate
+        (bcx, fcx.llargs.get(f.decl.inputs.(0).id), arg_ty);
+    bcx = copy_val(bcx, INIT, fcx.llretptr, arg, arg_ty).bcx;
+    bcx.build.RetVoid();
+    finish_fn(fcx, lltop);
+}
+
+
 fn trans_tag_variant(@local_ctxt cx, ast::node_id tag_id,
                      &ast::variant variant, int index,
                      &vec[ast::ty_param] ty_params) {
@@ -7729,6 +7767,9 @@ fn trans_item(@local_ctxt cx, &ast::item item) {
                      with *extend_path(cx, item.ident));
             trans_obj(sub_cx, item.span, ob, ctor_id, tps);
         }
+        case (ast::item_res(?decl, _, ?tps, ?ctor_id)) {
+            trans_res(cx, item.span, decl, ctor_id, tps);
+        }
         case (ast::item_mod(?m)) {
             auto sub_cx =
                 @rec(path=cx.path + [item.ident],
@@ -8062,6 +8103,9 @@ fn collect_item_2(&@crate_ctxt ccx, &@ast::item i, &vec[str] pt,
                 ccx.obj_methods.insert(m.node.id, ());
             }
         }
+        case (ast::item_res(?decl, _, ?tps, ?ctor_id)) {
+            decl_fn_and_pair(ccx, i.span, new_pt, "res_ctor", tps, ctor_id);
+        }
         case (_) { }
     }
 }
diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs
index 4455f09bdc2..e5eaadbb283 100644
--- a/src/comp/middle/tstate/pre_post_conditions.rs
+++ b/src/comp/middle/tstate/pre_post_conditions.rs
@@ -119,7 +119,7 @@ fn find_pre_post_item(&crate_ctxt ccx, &item i) {
                     ccx=ccx);
             find_pre_post_expr(fake_fcx, e);
         }
-        case (item_fn(?f, ?ps)) {
+        case (item_fn(?f, _)) {
             assert (ccx.fm.contains_key(i.id));
             auto fcx =
                 rec(enclosing=ccx.fm.get(i.id),
@@ -132,6 +132,13 @@ fn find_pre_post_item(&crate_ctxt ccx, &item i) {
         case (item_native_mod(?nm)) { find_pre_post_native_mod(nm); }
         case (item_ty(_, _)) { ret; }
         case (item_tag(_, _)) { ret; }
+        case (item_res(?dtor, ?dtor_id, _, _)) {
+            auto fcx = rec(enclosing=ccx.fm.get(dtor_id),
+                           id=dtor_id,
+                           name=i.ident,
+                           ccx=ccx);
+            find_pre_post_fn(fcx, dtor);
+        }
         case (item_obj(?o, _, _)) { find_pre_post_obj(ccx, o); }
     }
 }
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index de36d441838..0d5948eed6a 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -78,6 +78,7 @@ export mk_native;
 export mk_native_fn;
 export mk_nil;
 export mk_obj;
+export mk_res;
 export mk_param;
 export mk_port;
 export mk_ptr;
@@ -134,6 +135,7 @@ export ty_machine;
 export ty_native;
 export ty_nil;
 export ty_obj;
+export ty_res;
 export ty_param;
 export ty_port;
 export ty_ptr;
@@ -263,14 +265,12 @@ tag sty {
     ty_fn(ast::proto, vec[arg], t, controlflow, vec[@constr_def]);
     ty_native_fn(ast::native_abi, vec[arg], t);
     ty_obj(vec[method]);
+    ty_res(def_id, t);
     ty_var(int); // type variable
-
     ty_param(uint); // fn/tag type param
-
     ty_type;
     ty_native;
     // TODO: ty_fn_arg(t), for a possibly-aliased function argument
-
 }
 
 type constr_def = spanned[constr_general[uint]];
@@ -492,6 +492,7 @@ fn mk_raw_ty(&ctxt cx, &sty st, &option::t[str] cname) -> raw_t {
                                  m.output);
             }
         }
+        case (ty_res(_, ?tt)) { derive_flags_t(cx, has_params, has_vars, tt);}
     }
     ret rec(struct=st,
             cname=cname,
@@ -598,6 +599,10 @@ fn mk_obj(&ctxt cx, &vec[method] meths) -> t {
     ret gen_ty(cx, ty_obj(meths));
 }
 
+fn mk_res(&ctxt cx, &ast::def_id did, &t inner) -> t {
+    ret gen_ty(cx, ty_res(did, inner));
+}
+
 fn mk_var(&ctxt cx, int v) -> t { ret gen_ty(cx, ty_var(v)); }
 
 fn mk_param(&ctxt cx, uint n) -> t { ret gen_ty(cx, ty_param(n)); }
@@ -679,6 +684,7 @@ fn walk_ty(&ctxt cx, ty_walk walker, t ty) {
                 walk_ty(cx, walker, m.output);
             }
         }
+        case (ty_res(_, ?sub)) { walk_ty(cx, walker, sub); }
         case (ty_var(_)) {/* no-op */ }
         case (ty_param(_)) {/* no-op */ }
     }
@@ -811,6 +817,9 @@ fn fold_ty(&ctxt cx, fold_mode fld, t ty_0) -> t {
             }
             ty = copy_cname(cx, mk_obj(cx, new_methods), ty);
         }
+        case (ty_res(?did, ?subty)) {
+            ty = copy_cname(cx, mk_res(cx, did, fold_ty(cx, fld, subty)), ty);
+        }
         case (ty_var(?id)) {
             alt (fld) {
                 case (fm_var(?folder)) { ty = folder(id); }
@@ -880,6 +889,7 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool {
         case (ty_tag(_, _)) { ret true; }
         case (ty_fn(_, _, _, _, _)) { ret true; }
         case (ty_obj(_)) { ret true; }
+        case (ty_res(_, _)) { ret true; }
         case (ty_ivec(_)) { ret true; }
         case (ty_istr) { ret true; }
         case (_) { ret false; }
@@ -1091,6 +1101,7 @@ fn type_has_dynamic_size(&ctxt cx, &t ty) -> bool {
         case (ty_fn(_,_,_,_,_)) { ret false; }
         case (ty_native_fn(_,_,_)) { ret false; }
         case (ty_obj(_)) { ret false; }
+        case (ty_res(_, ?sub)) { ret type_has_dynamic_size(cx, sub); }
         case (ty_var(_)) { fail "ty_var in type_has_dynamic_size()"; }
         case (ty_param(_)) { ret true; }
         case (ty_type) { ret false; }
@@ -1196,6 +1207,7 @@ fn type_owns_heap_mem(&ctxt cx, &t ty) -> bool {
                 if (type_owns_heap_mem(cx, f.mt.ty)) { result = true; }
             }
         }
+        case (ty_res(_, ?inner)) { result = type_owns_heap_mem(cx, inner); }
 
         case (ty_ptr(_)) { result = false; }
         case (ty_port(_)) { result = false; }
@@ -1289,9 +1301,8 @@ fn hash_type_structure(&sty st) -> uint {
             for (field f in fields) { h += h << 5u + hash_ty(f.mt.ty); }
             ret h;
         }
-        case (
-             // ???
-             ty_fn(_, ?args, ?rty, _, _)) {
+        // ???
+        case (ty_fn(_, ?args, ?rty, _, _)) {
             ret hash_fn(27u, args, rty);
         }
         case (ty_native_fn(_, ?args, ?rty)) { ret hash_fn(28u, args, rty); }
@@ -1306,6 +1317,7 @@ fn hash_type_structure(&sty st) -> uint {
         case (ty_native) { ret 33u; }
         case (ty_bot) { ret 34u; }
         case (ty_ptr(?mt)) { ret hash_subty(35u, mt.ty); }
+        case (ty_res(?did, ?sub)) { ret hash_subty(hash_def(18u, did), sub); }
     }
 }
 
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 353eb3997df..4ad7400dc99 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -526,8 +526,7 @@ mod collect {
         auto methods = get_obj_method_types(cx, obj_info);
         auto t_obj = ty::mk_obj(cx.tcx, ty::sort_methods(methods));
         t_obj = ty::rename(cx.tcx, t_obj, id);
-        auto ty_param_count = vec::len[ast::ty_param](ty_params);
-        ret tup(ty_param_count, t_obj);
+        ret tup(vec::len(ty_params), t_obj);
     }
     fn ty_of_obj_ctor(@ctxt cx, &ast::ident id, &ast::_obj obj_info,
                       ast::node_id ctor_id, &vec[ast::ty_param] ty_params) ->
@@ -579,6 +578,13 @@ mod collect {
                 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(vec::len(tps), ty::mk_res
+                                 (cx.tcx, local_def(it.id), t_arg.ty));
+                cx.tcx.tcache.insert(local_def(it.id), t_res);
+                ret t_res;
+            }
             case (ast::item_tag(_, ?tps)) {
                 // Create a new generic polytype.
 
@@ -729,6 +735,18 @@ mod collect {
                     }
                 }
             }
+            case (ast::item_res(?f, ?dtor_id, ?tps, ?ctor_id)) {
+                auto t_arg = ty_of_arg(cx, f.decl.inputs.(0));
+                auto t_res = ty::mk_res(cx.tcx, local_def(it.id), t_arg.ty);
+                auto t_ctor = ty::mk_fn(cx.tcx, ast::proto_fn, [t_arg],
+                                        t_res, ast::return, []);
+                auto t_dtor = ty::mk_fn(cx.tcx, ast::proto_fn, [t_arg],
+                                        ty::mk_nil(cx.tcx), ast::return, []);
+                write::ty_only(cx.tcx, ctor_id, t_ctor);
+                cx.tcx.tcache.insert(local_def(ctor_id),
+                                     tup(vec::len(tps), t_ctor));
+                write::ty_only(cx.tcx, dtor_id, t_dtor);
+            }
             case (_) {
                 // This call populates the type cache with the converted type
                 // of the item in passing. All we have to do here is to write
@@ -2337,6 +2355,9 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) {
         case (ast::item_fn(?f, _)) {
             check_fn(ccx, f.decl, f.proto, f.body, it.id);
         }
+        case (ast::item_res(?f, ?dtor_id, _, _)) {
+            check_fn(ccx, f.decl, f.proto, f.body, dtor_id);
+        }
         case (ast::item_obj(?ob, _, _)) {
             // We're entering an object, so gather up the info we need.
 
diff --git a/src/comp/middle/visit.rs b/src/comp/middle/visit.rs
index 48abf3f7a80..53efe81c4a2 100644
--- a/src/comp/middle/visit.rs
+++ b/src/comp/middle/visit.rs
@@ -115,6 +115,9 @@ fn visit_item[E](&@item i, &E e, &vt[E] v) {
             }
         }
         case (item_ty(?t, _)) { vt(v).visit_ty(t, e, v); }
+        case (item_res(?f, ?dtor_id, ?tps, _)) {
+            vt(v).visit_fn(f, tps, i.span, i.ident, dtor_id, e, v);
+        }
         case (item_tag(?variants, _)) {
             for (variant vr in variants) {
                 for (variant_arg va in vr.node.args) {
diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs
index d2e9343a33d..821a00ad450 100644
--- a/src/comp/middle/walk.rs
+++ b/src/comp/middle/walk.rs
@@ -105,6 +105,9 @@ fn walk_item(&ast_visitor v, @ast::item i) {
         case (ast::item_mod(?m)) { walk_mod(v, m); }
         case (ast::item_native_mod(?nm)) { walk_native_mod(v, nm); }
         case (ast::item_ty(?t, _)) { walk_ty(v, t); }
+        case (ast::item_res(?f, ?dtor_id, _, _)) {
+            walk_fn(v, f, i.span, some(i.ident), dtor_id);
+        }
         case (ast::item_tag(?variants, _)) {
             for (ast::variant vr in variants) {
                 for (ast::variant_arg va in vr.node.args) {
diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs
index 00985834620..23f2efc3d04 100644
--- a/src/comp/pretty/pprust.rs
+++ b/src/comp/pretty/pprust.rs
@@ -436,6 +436,18 @@ fn print_item(&ps s, &@ast::item item) {
             }
             bclose(s, item.span);
         }
+        case (ast::item_res(?dt, ?dt_id, ?tps, ?ct_id)) {
+            head(s, "res");
+            word(s.s, item.ident);
+            print_type_params(s, tps);
+            popen(s);
+            print_type(s, *dt.decl.inputs.(0).ty);
+            space(s.s);
+            word(s.s, dt.decl.inputs.(0).ident);
+            pclose(s);
+            space(s.s);
+            print_block(s, dt.body);
+        }
     }
 
     // Print the node ID if necessary. TODO: type as well.