about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2012-01-25 16:44:51 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2012-01-25 20:47:11 +0100
commit2d4d8e8bdbe2c6d0656c4887ad8ccadcb8a39966 (patch)
tree80aa0c77bcad42213b2db6d2f3c301f97f52e110 /src/comp
parent76aabbe99d598dc42e8e3723d98516422bd26d33 (diff)
downloadrust-2d4d8e8bdbe2c6d0656c4887ad8ccadcb8a39966.tar.gz
rust-2d4d8e8bdbe2c6d0656c4887ad8ccadcb8a39966.zip
Implement implicit self type parameters for ifaces
Closes #1661
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/metadata/decoder.rs16
-rw-r--r--src/comp/middle/resolve.rs2
-rw-r--r--src/comp/middle/trans.rs2
-rw-r--r--src/comp/middle/ty.rs35
-rw-r--r--src/comp/middle/typeck.rs109
-rw-r--r--src/comp/syntax/parse/parser.rs5
-rw-r--r--src/comp/syntax/print/pprust.rs3
7 files changed, 100 insertions, 72 deletions
diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs
index fb0e25842c2..ffea622d022 100644
--- a/src/comp/metadata/decoder.rs
+++ b/src/comp/metadata/decoder.rs
@@ -128,14 +128,15 @@ fn item_impl_iface(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
     result
 }
 
-fn item_ty_param_bounds(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
-    -> @[ty::param_bounds] {
-    let bounds = [];
+fn item_ty_param_bounds(item: ebml::doc, tcx: ty::ctxt, cdata: cmd,
+                        skip: bool) -> @[ty::param_bounds] {
+    let bounds = [], skip = skip;
     ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds) {|p|
         let bd = parse_bounds_data(p.data, p.start, cdata.cnum, tcx, {|did|
             translate_def_id(cdata, did)
         });
-        bounds += [bd];
+        if skip { skip = false; }
+        else { bounds += [bd]; }
     }
     @bounds
 }
@@ -218,8 +219,9 @@ fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
     -> ty::ty_param_bounds_and_ty {
     let item = lookup_item(id, cdata.data);
     let t = item_type(item, tcx, cdata);
-    let tp_bounds = if family_has_type_params(item_family(item)) {
-        item_ty_param_bounds(item, tcx, cdata)
+    let family = item_family(item);
+    let tp_bounds = if family_has_type_params(family) {
+        item_ty_param_bounds(item, tcx, cdata, family == ('I' as u8))
     } else { @[] };
     ret {bounds: tp_bounds, ty: t};
 }
@@ -302,7 +304,7 @@ fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
     let data = cdata.data;
     let item = lookup_item(id, data), result = [];
     ebml::tagged_docs(item, tag_item_method) {|mth|
-        let bounds = item_ty_param_bounds(mth, tcx, cdata);
+        let bounds = item_ty_param_bounds(mth, tcx, cdata, false);
         let name = item_name(mth);
         let ty = doc_type(mth, tcx, cdata);
         let fty = alt ty::struct(tcx, ty) { ty::ty_fn(f) { f } };
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 6515b26644b..ce799e5e0bb 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -1014,7 +1014,7 @@ fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param])
         } { ret some(ast::def_ty_param(local_def(tp.id), n)); }
         n += 1u;
     }
-    ret none::<def>;
+    ret none;
 }
 
 fn lookup_in_pat(e: env, name: ident, pat: @ast::pat) -> option::t<def_id> {
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index b91cbd57118..0004f81cb4e 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -892,7 +892,7 @@ fn linearize_ty_params(cx: @block_ctxt, t: ty::t) ->
     }
     let x = @{cx: cx, mutable vals: param_vals, mutable defs: param_defs};
     let f = bind linearizer(x, _);
-    ty::walk_ty(bcx_tcx(cx), f, t);
+    ty::walk_ty(bcx_tcx(cx), t, f);
     ret {params: x.defs, descs: x.vals};
 }
 
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index dc4cf70d83b..77c35cf0f20 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -673,41 +673,37 @@ pure fn ty_name(cx: ctxt, typ: t) -> option::t<@str> {
     }
 }
 
-
-// Type folds
-type ty_walk = fn@(t);
-
-fn walk_ty(cx: ctxt, walker: ty_walk, ty: t) {
+fn walk_ty(cx: ctxt, ty: t, walker: fn(t)) {
     alt struct(cx, ty) {
       ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
       ty_str | ty_send_type | ty_type | ty_native(_) |
       ty_opaque_closure_ptr(_) {
         /* no-op */
       }
-      ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, walker, tm.ty); }
+      ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, tm.ty, walker); }
       ty_enum(_, subtys) | ty_iface(_, subtys) {
-        for subty: t in subtys { walk_ty(cx, walker, subty); }
+        for subty: t in subtys { walk_ty(cx, subty, walker); }
       }
       ty_rec(fields) {
-        for fl: field in fields { walk_ty(cx, walker, fl.mt.ty); }
+        for fl: field in fields { walk_ty(cx, fl.mt.ty, walker); }
       }
-      ty_tup(ts) { for tt in ts { walk_ty(cx, walker, tt); } }
+      ty_tup(ts) { for tt in ts { walk_ty(cx, tt, walker); } }
       ty_fn(f) {
-        for a: arg in f.inputs { walk_ty(cx, walker, a.ty); }
-        walk_ty(cx, walker, f.output);
+        for a: arg in f.inputs { walk_ty(cx, a.ty, walker); }
+        walk_ty(cx, f.output, walker);
       }
       ty_native_fn(args, ret_ty) {
-        for a: arg in args { walk_ty(cx, walker, a.ty); }
-        walk_ty(cx, walker, ret_ty);
+        for a: arg in args { walk_ty(cx, a.ty, walker); }
+        walk_ty(cx, ret_ty, walker);
       }
       ty_res(_, sub, tps) {
-        walk_ty(cx, walker, sub);
-        for tp: t in tps { walk_ty(cx, walker, tp); }
+        walk_ty(cx, sub, walker);
+        for tp: t in tps { walk_ty(cx, tp, walker); }
       }
-      ty_constr(sub, _) { walk_ty(cx, walker, sub); }
+      ty_constr(sub, _) { walk_ty(cx, sub, walker); }
       ty_var(_) {/* no-op */ }
       ty_param(_, _) {/* no-op */ }
-      ty_uniq(tm) { walk_ty(cx, walker, tm.ty); }
+      ty_uniq(tm) { walk_ty(cx, tm.ty, walker); }
     }
     walker(ty);
 }
@@ -1273,7 +1269,7 @@ fn vars_in_type(cx: ctxt, ty: t) -> [int] {
         alt struct(cx, ty) { ty_var(v) { *vars += [v]; } _ { } }
     }
     let rslt: @mutable [int] = @mutable [];
-    walk_ty(cx, bind collect_var(cx, rslt, _), ty);
+    walk_ty(cx, ty) {|t| collect_var(cx, rslt, t)}
     // Works because of a "convenient" bug that lets us
     // return a mutable vec as if it's immutable
     ret *rslt;
@@ -1529,7 +1525,7 @@ fn count_ty_params(cx: ctxt, ty: t) -> uint {
     }
     let param_indices: @mutable [uint] = @mutable [];
     let f = bind counter(cx, param_indices, _);
-    walk_ty(cx, f, ty);
+    walk_ty(cx, ty, f);
     ret vec::len::<uint>(*param_indices);
 }
 
@@ -2695,7 +2691,6 @@ fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
     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.
-
         ret cx.tcache.get(did);
     }
     alt cx.tcache.find(did) {
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 5d0c1af173d..63de1e4e761 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -415,16 +415,15 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
         ret tpt;
       }
       ast::item_iface(tps, ms) {
-        let {bounds, params} = mk_ty_params(tcx, tps);
-        let t = ty::mk_named(tcx, ty::mk_iface(tcx, local_def(it.id),
-                                               params),
+        let s_tp = vec::len(tps) - 1u;
+        tcx.ty_param_bounds.insert(tps[s_tp].id, @[]);
+        let {bounds, params} = mk_ty_params(tcx, vec::slice(tps, 0u, s_tp));
+        let t = ty::mk_named(tcx, ty::mk_iface(tcx, local_def(it.id), params),
                              @it.ident);
         let tpt = {bounds: bounds, ty: t};
         tcx.tcache.insert(local_def(it.id), tpt);
         ret tpt;
       }
-      ast::item_impl(_, _, _, _) | ast::item_mod(_) |
-      ast::item_native_mod(_) { fail; }
     }
 }
 fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item)
@@ -604,12 +603,20 @@ fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param])
 }
 
 fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
-                       impl_tps: uint, if_m: ty::method, substs: [ty::t]) {
+                       impl_tps: uint, if_m: ty::method, substs: [ty::t])
+    -> ty::t {
     if impl_m.tps != if_m.tps {
         tcx.sess.span_err(sp, "method `" + if_m.ident +
                           "` has an incompatible set of type parameters");
+        ty::mk_fn(tcx, impl_m.fty)
     } else {
-        let impl_fty = ty::mk_fn(tcx, impl_m.fty);
+        let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f|
+            alt ty::struct(tcx, f.ty) {
+              ty::ty_param(0u, _) { {mode: ast::by_ref with i} }
+              _ { i }
+            }
+        });
+        let impl_fty = ty::mk_fn(tcx, {inputs: auto_modes with impl_m.fty});
         // Add dummy substs for the parameters of the impl method
         let substs = substs + vec::init_fn(vec::len(*if_m.tps), {|i|
             ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0})
@@ -621,8 +628,9 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
             tcx.sess.span_err(sp, "method `" + if_m.ident +
                               "` has an incompatible type: " +
                               ty::type_err_to_str(err));
+            impl_fty
           }
-          _ {}
+          ty::unify::ures_ok(tp) { tp }
         }
     }
 }
@@ -690,15 +698,15 @@ mod collect {
             for m in ms {
                 let bounds = ty_param_bounds(cx.tcx, m_collect, m.tps);
                 let mty = ty_of_method(cx.tcx, m_collect, m);
-                my_methods += [mty];
+                my_methods += [{mty: mty, id: m.id}];
                 let fty = ty::mk_fn(cx.tcx, mty.fty);
                 cx.tcx.tcache.insert(local_def(m.id),
                                      {bounds: @(*i_bounds + *bounds),
                                       ty: fty});
                 write::ty_only(cx.tcx, m.id, fty);
             }
-            write::ty_only(cx.tcx, it.id, ast_ty_to_ty(cx.tcx, m_collect,
-                                                       selfty));
+            let selfty = ast_ty_to_ty(cx.tcx, m_collect, selfty);
+            write::ty_only(cx.tcx, it.id, selfty);
             alt ifce {
               some(t) {
                 let iface_ty = ast_ty_to_ty(cx.tcx, m_collect, t);
@@ -708,10 +716,18 @@ mod collect {
                   ty::ty_iface(did, tys) {
                     for if_m in *ty::iface_methods(cx.tcx, did) {
                         alt vec::find(my_methods,
-                                      {|m| if_m.ident == m.ident}) {
-                          some(m) {
-                            compare_impl_method(cx.tcx, t.span, m,
-                                                vec::len(tps), if_m, tys);
+                                      {|m| if_m.ident == m.mty.ident}) {
+                          some({mty: m, id}) {
+                            let mt = compare_impl_method(
+                                cx.tcx, t.span, m, vec::len(tps), if_m,
+                                tys + [selfty]);
+                            let old = cx.tcx.tcache.get(local_def(id));
+                            if old.ty != mt {
+                                cx.tcx.tcache.insert(local_def(id),
+                                                     {bounds: old.bounds,
+                                                      ty: mt});
+                                write::ty_only(cx.tcx, id, mt);
+                            }
                           }
                           none {
                             cx.tcx.sess.span_err(t.span, "missing method `" +
@@ -1501,7 +1517,7 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
                     let m = ifce_methods[pos];
                     ret some({method_ty: ty::mk_fn(tcx, m.fty),
                               n_tps: vec::len(*m.tps),
-                              substs: tps,
+                              substs: tps + [ty],
                               origin: method_param(iid, pos, n, bound_n)});
                   }
                   _ {}
@@ -1519,7 +1535,7 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
             if m.ident == name {
                 ret some({method_ty: ty::mk_fn(tcx, m.fty),
                           n_tps: vec::len(*m.tps),
-                          substs: tps,
+                          substs: tps + [ty::mk_int(tcx)],
                           origin: method_iface(i)});
             }
             i += 1u;
@@ -1528,17 +1544,6 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
       _ {}
     }
 
-    fn ty_from_did(tcx: ty::ctxt, did: ast::def_id) -> ty::t {
-        if did.crate == ast::local_crate {
-            alt tcx.items.get(did.node) {
-              ast_map::node_method(m) {
-                let mt = ty_of_method(tcx, m_check, m);
-                ty::mk_fn(tcx, mt.fty)
-              }
-            }
-        } else { csearch::get_type(tcx, did).ty }
-    }
-
     let result = none;
     std::list::iter(isc) {|impls|
         if option::is_some(result) { ret; }
@@ -1557,7 +1562,7 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
                             sp, "multiple applicable methods in scope");
                     } else {
                         result = some({
-                            method_ty: ty_from_did(tcx, m.did),
+                            method_ty: ty::lookup_item_type(tcx, m.did).ty,
                             n_tps: m.n_tps,
                             substs: vars,
                             origin: method_static(m.did)
@@ -1812,16 +1817,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
 
         check_binop_type_compat(fcx, expr.span, lhs_t, binop);
 
-        let t =
-            alt binop {
-              ast::eq { ty::mk_bool(tcx) }
-              ast::lt { ty::mk_bool(tcx) }
-              ast::le { ty::mk_bool(tcx) }
-              ast::ne { ty::mk_bool(tcx) }
-              ast::ge { ty::mk_bool(tcx) }
-              ast::gt { ty::mk_bool(tcx) }
-              _ { lhs_t }
-            };
+        let t = alt binop {
+          ast::eq | ast::lt | ast::le | ast::ne | ast::ge |
+          ast::gt { ty::mk_bool(tcx) }
+          _ { lhs_t }
+        };
         write::ty_only_fixup(fcx, id, t);
       }
       ast::expr_unary(unop, oper) {
@@ -2915,9 +2915,38 @@ mod dict {
             }
           }
           ast::expr_cast(src, _) {
+            // Ifaces that refer to a self type can not be cast to -- callers
+            // wouldn't know what self refers to.
+            fn type_refers_to_self(tcx: ty::ctxt, t: ty::t, s_param: uint)
+                -> bool {
+                let found = false;
+                if ty::type_contains_params(tcx, t) {
+                    ty::walk_ty(tcx, t) {|t|
+                        alt ty::struct(tcx, t) {
+                          ty::ty_param(n, _) if n == s_param { found = true; }
+                          _ {}
+                        }
+                    }
+                }
+                found
+            }
+            fn method_refers_to_self(tcx: ty::ctxt, m: ty::method,
+                                     s_param: uint) -> bool {
+                vec::any(m.fty.inputs, {|in|
+                    type_refers_to_self(tcx, in.ty, s_param)
+                }) || type_refers_to_self(tcx, m.fty.output, s_param)
+            }
             let target_ty = expr_ty(cx.tcx, ex);
             alt ty::struct(cx.tcx, target_ty) {
-              ty::ty_iface(_, _) {
+              ty::ty_iface(id, tps) {
+                for m in *ty::iface_methods(cx.tcx, id) {
+                    if method_refers_to_self(cx.tcx, m, vec::len(tps)) {
+                        cx.tcx.sess.span_err(
+                            ex.span, "can not cast to an iface type that \
+                                      refers to `self` " + m.ident);
+                        break;
+                    }
+                }
                 let impls = cx.impl_map.get(ex.id);
                 let dict = lookup_dict(fcx, impls, ex.span,
                                        expr_ty(cx.tcx, src), target_ty);
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 602e209e573..eca22f38adf 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -1831,9 +1831,10 @@ fn parse_method(p: parser) -> @ast::method {
 
 fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item {
     let lo = p.last_span.lo, ident = parse_ident(p),
-        tps = parse_ty_params(p), meths = parse_ty_methods(p);
+        tps = parse_ty_params(p), meths = parse_ty_methods(p),
+        self_tp = {ident: "self", id: p.get_id(), bounds: @[]};
     ret mk_item(p, lo, p.last_span.hi, ident,
-                ast::item_iface(tps, meths), attrs);
+                ast::item_iface(tps + [self_tp], meths), attrs);
 }
 
 // Parses three variants (with the initial params always optional):
diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs
index ad6f96e9a1b..bdfc06b403b 100644
--- a/src/comp/syntax/print/pprust.rs
+++ b/src/comp/syntax/print/pprust.rs
@@ -488,7 +488,8 @@ fn print_item(s: ps, &&item: @ast::item) {
       ast::item_iface(tps, methods) {
         head(s, "iface");
         word(s.s, item.ident);
-        print_type_params(s, tps);
+        print_type_params(s, vec::slice(tps, 0u, vec::len(tps) - 1u));
+        nbsp(s);
         bopen(s);
         for meth in methods { print_ty_method(s, meth); }
         bclose(s, item.span);