about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-12-16 11:37:38 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2011-12-16 13:47:48 +0100
commitd529757515671d5826d8d2203ce0a4f82a3bdee5 (patch)
tree1886bd880e0e912f1d962cd9a1fd1a0035634c66 /src/comp
parentcff6bdd03616b6f20028ec8568d03363ccc3f9f2 (diff)
downloadrust-d529757515671d5826d8d2203ce0a4f82a3bdee5.tar.gz
rust-d529757515671d5826d8d2203ce0a4f82a3bdee5.zip
Make polymorphic impl methods work
Something will still have to be done to the AST to make it possible to
say `x.foo::<int>()`, since currently field access never allows type
parameters.

Issue #1227
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/middle/resolve.rs3
-rw-r--r--src/comp/middle/trans.rs26
-rw-r--r--src/comp/middle/typeck.rs81
-rw-r--r--src/comp/syntax/ast.rs2
-rw-r--r--src/comp/syntax/fold.rs3
-rw-r--r--src/comp/syntax/parse/parser.rs11
-rw-r--r--src/comp/syntax/visit.rs12
7 files changed, 82 insertions, 56 deletions
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index bc095e992f0..9fdba389c24 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -751,10 +751,11 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
               ast::item_obj(ob, ty_params, _) {
                 ret lookup_in_obj(name, ob, ty_params, ns, it.id);
               }
-              ast::item_impl(_, _, _) {
+              ast::item_impl(ty_params, _, _) {
                 if (name == "self" && ns == ns_value) {
                     ret some(ast::def_self(local_def(it.id)));
                 }
+                if ns == ns_type { ret lookup_in_ty_params(name, ty_params); }
               }
               ast::item_tag(_, ty_params) {
                 if ns == ns_type { ret lookup_in_ty_params(name, ty_params); }
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 2c724ba8fca..37e35ee3efa 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -4353,15 +4353,19 @@ fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg,
     // way.
     let arg_n = 2u;
     alt ty_self {
-      obj_self(tt) | impl_self(tt) { cx.llself = some({v: cx.llenv, t: tt}); }
-      no_self. {
-        let i = 0u;
-        for tp: ast::ty_param in ty_params {
+      obj_self(tt) | impl_self(tt) {
+        cx.llself = some({v: cx.llenv, t: tt});
+      }
+      no_self. {}
+    }
+    alt ty_self {
+      obj_self(_) {}
+      _ {
+        for tp in ty_params {
             let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
             assert (llarg as int != 0);
             cx.lltydescs += [llarg];
             arg_n += 1u;
-            i += 1u;
         }
       }
     }
@@ -4659,14 +4663,14 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
 }
 
 fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
-              id: ast::node_id) {
+              id: ast::node_id, tps: [ast::ty_param]) {
     let sub_cx = extend_path(cx, name);
     for m in methods {
         alt cx.ccx.item_ids.find(m.node.id) {
           some(llfn) {
             trans_fn(extend_path(sub_cx, m.node.ident), m.span, m.node.meth,
                      llfn, impl_self(ty::node_id_to_monotype(cx.ccx.tcx, id)),
-                     [], m.node.id);
+                     tps + m.node.tps, m.node.id);
           }
         }
     }
@@ -4980,7 +4984,9 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
                  with *extend_path(cx, item.ident)};
         trans_obj(sub_cx, item.span, ob, ctor_id, tps);
       }
-      ast::item_impl(_, _, ms) { trans_impl(cx, item.ident, ms, item.id); }
+      ast::item_impl(tps, _, ms) {
+        trans_impl(cx, item.ident, ms, item.id, tps);
+      }
       ast::item_res(dtor, dtor_id, tps, ctor_id) {
         trans_res_ctor(cx, item.span, dtor, ctor_id, tps);
 
@@ -5304,11 +5310,11 @@ fn collect_item_2(ccx: @crate_ctxt, i: @ast::item, &&pt: [str],
             ccx.obj_methods.insert(m.node.id, ());
         }
       }
-      ast::item_impl(_, _, methods) {
+      ast::item_impl(tps, _, methods) {
         let name = ccx.names.next(i.ident);
         for m in methods {
             register_fn(ccx, i.span, pt + [name, m.node.ident],
-                        "impl_method", [], m.node.id);
+                        "impl_method", tps + m.node.tps, m.node.id);
         }
       }
       ast::item_res(_, dtor_id, tps, ctor_id) {
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index d697421bde4..d86215a14c0 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -962,8 +962,7 @@ mod writeback {
                                   typ) {
           fix_ok(new_type) { ret some(new_type); }
           fix_err(vid) {
-            fcx.ccx.tcx.sess.span_err(sp,
-                                      "cannot determine a type \
+            fcx.ccx.tcx.sess.span_err(sp, "cannot determine a type \
                                            for this expression");
             ret none;
           }
@@ -1461,6 +1460,42 @@ fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool {
     ret check_expr_with_unifier(fcx, expr, demand::simple, expected);
 }
 
+// FIXME[impl] notice/resolve conflicts
+fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
+                 name: ast::ident, ty: ty::t)
+    -> option::t<{method: @ast::method, ids: [int]}> {
+    let result = none;
+    std::list::iter(isc) {|impls|
+        for im in *impls {
+            alt im.node {
+              ast::item_impl(tps, slf, mthds) {
+                let self_ty = ast_ty_to_ty_crate(fcx.ccx, slf);
+                let tp_count = vec::len(tps);
+                let {ids, ty: self_ty} = if tp_count > 0u {
+                    bind_params_in_type(ast_util::dummy_sp(), fcx.ccx.tcx,
+                                        bind next_ty_var_id(fcx), self_ty,
+                                        tp_count)
+                } else { {ids: [], ty: self_ty} };
+                // FIXME[impl] Don't unify in the current fcx, use
+                // scratch context
+                alt unify::unify(fcx, ty, self_ty) {
+                  ures_ok(_) {
+                    for m in mthds {
+                        if m.node.ident == name {
+                            result = some({method: m, ids: ids});
+                            ret;
+                        }
+                    }
+                  }
+                  _ {}
+                }
+              }
+            }
+        }
+    }
+    result
+}
+
 fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
                            expected: ty::t) -> bool {
     //log_err "typechecking expr " + syntax::print::pprust::expr_to_str(expr);
@@ -2089,42 +2124,24 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         }
       }
       ast::expr_field(base, field) {
-        // FIXME proper type compare, notice conflicts
-        fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
-                         name: ast::ident, ty: ty::t)
-            -> option::t<@ast::method> {
-            let result = none;
-            std::list::iter(isc) {|impls|
-                for im in *impls {
-                    alt im.node {
-                      ast::item_impl(_, slf, mthds) {
-                        let self_ty = ast_ty_to_ty_crate(fcx.ccx, slf);
-                        alt unify::unify(fcx, ty, self_ty) {
-                          ures_ok(_) {}
-                          _ { cont; }
-                        }
-                        for m in mthds {
-                            if m.node.ident == name {
-                                result = some(m);
-                                ret;
-                            }
-                        }
-                      }
-                    }
-                }
-            }
-            result
-        }
-
         bot |= check_expr(fcx, base);
         let base_t = expr_ty(tcx, base);
         let iscope = fcx.ccx.impl_map.get(expr.id);
         alt lookup_method(fcx, iscope, field, base_t) {
-          some(method) {
-            let mt = ty_of_method(fcx.ccx.tcx, m_check, method);
+          some({method, ids}) {
+            let mt = ty_of_method(fcx.ccx.tcx, m_check, method), ids = ids;
             let fty = ty::mk_fn(fcx.ccx.tcx, mt.proto, mt.inputs,
                                 mt.output, mt.cf, mt.constrs);
-            write::ty_only_fixup(fcx, id, fty);
+            let tp_count = vec::len(method.node.tps);
+            if tp_count > 0u {
+                let b = bind_params_in_type(expr.span, tcx,
+                                            bind next_ty_var_id(fcx),
+                                            fty, tp_count);
+                ids += b.ids;
+                fty = b.ty;
+            }
+            let substs = vec::map({|id| ty::mk_var(tcx, id)}, ids);
+            write::ty_fixup(fcx, id, {substs: some(substs), ty: fty});
             fcx.ccx.method_map.insert(id, local_def(method.node.id));
           }
           _ {
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index fd79869c27b..d85849b2571 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -423,7 +423,7 @@ tag ret_style {
 
 type _fn = {decl: fn_decl, proto: proto, body: blk};
 
-type method_ = {ident: ident, meth: _fn, id: node_id};
+type method_ = {ident: ident, meth: _fn, id: node_id, tps: [ty_param]};
 
 type method = spanned<method_>;
 
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index aa949b11f34..b3a48cc418c 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -246,7 +246,8 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
 }
 
 fn noop_fold_method(m: method_, fld: ast_fold) -> method_ {
-    ret {ident: fld.fold_ident(m.ident), meth: fld.fold_fn(m.meth), id: m.id};
+    ret {ident: fld.fold_ident(m.ident), meth: fld.fold_fn(m.meth)
+         with m};
 }
 
 
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 3d00c333ad4..12df9ecd1ad 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -854,7 +854,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr {
         while p.peek() != token::RBRACE {
             if eat_word(p, "with") {
                 inner_obj = some(parse_expr(p));
-            } else { meths += [parse_method(p)]; }
+            } else { meths += [parse_method(p, false)]; }
         }
         hi = p.get_hi_pos();
         expect(p, token::RBRACE);
@@ -1832,12 +1832,13 @@ fn parse_anon_obj_field(p: parser) -> ast::anon_obj_field {
     ret {mut: mut, ty: ty, expr: expr, ident: ident, id: p.get_id()};
 }
 
-fn parse_method(p: parser) -> @ast::method {
+fn parse_method(p: parser, allow_tps: bool) -> @ast::method {
     let lo = p.get_lo_pos();
     let proto = parse_method_proto(p);
     let ident = parse_value_ident(p);
+    let tps = allow_tps ? parse_ty_params(p) : [];
     let f = parse_fn(p, proto, ast::impure_fn, ast::il_normal);
-    let meth = {ident: ident, meth: f, id: p.get_id()};
+    let meth = {ident: ident, meth: f, id: p.get_id(), tps: tps};
     ret @spanned(lo, f.body.span.hi, meth);
 }
 
@@ -1850,7 +1851,7 @@ fn parse_item_obj(p: parser, attrs: [ast::attribute]) -> @ast::item {
                   parse_obj_field, p);
     let meths: [@ast::method] = [];
     expect(p, token::LBRACE);
-    while p.peek() != token::RBRACE { meths += [parse_method(p)]; }
+    while p.peek() != token::RBRACE { meths += [parse_method(p, false)]; }
     let hi = p.get_hi_pos();
     expect(p, token::RBRACE);
     let ob: ast::_obj = {fields: fields.node, methods: meths};
@@ -1864,7 +1865,7 @@ fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item {
     expect_word(p, "for");
     let ty = parse_ty(p, false), meths = [];
     expect(p, token::LBRACE);
-    while !eat(p, token::RBRACE) { meths += [parse_method(p)]; }
+    while !eat(p, token::RBRACE) { meths += [parse_method(p, true)]; }
     ret mk_item(p, lo, p.get_last_hi_pos(), ident,
                 ast::item_impl(tps, ty, meths), attrs);
 }
diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs
index 5091c2d9ea0..a1feec5bec9 100644
--- a/src/comp/syntax/visit.rs
+++ b/src/comp/syntax/visit.rs
@@ -101,15 +101,15 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
       item_obj(ob, _, _) {
         for f: obj_field in ob.fields { v.visit_ty(f.ty, e, v); }
         for m: @method in ob.methods {
-            v.visit_fn(m.node.meth, [], m.span, some(m.node.ident), m.node.id,
-                       e, v);
+            v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident),
+                       m.node.id, e, v);
         }
       }
       item_impl(_, ty, methods) {
         visit_ty(ty, e, v);
         for m in methods {
-            v.visit_fn(m.node.meth, [], m.span, some(m.node.ident), m.node.id,
-                       e, v);
+            v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident),
+                       m.node.id, e, v);
         }
       }
     }
@@ -321,8 +321,8 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
           some(ex) { v.visit_expr(ex, e, v); }
         }
         for m: @method in anon_obj.methods {
-            v.visit_fn(m.node.meth, [], m.span, some(m.node.ident), m.node.id,
-                       e, v);
+            v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident),
+                       m.node.id, e, v);
         }
       }
       expr_mac(mac) { visit_mac(mac, e, v); }