Skip to content

Commit d529757

Browse files
committed
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
1 parent cff6bdd commit d529757

File tree

7 files changed

+82
-56
lines changed

7 files changed

+82
-56
lines changed

src/comp/middle/resolve.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,10 +751,11 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
751751
ast::item_obj(ob, ty_params, _) {
752752
ret lookup_in_obj(name, ob, ty_params, ns, it.id);
753753
}
754-
ast::item_impl(_, _, _) {
754+
ast::item_impl(ty_params, _, _) {
755755
if (name == "self" && ns == ns_value) {
756756
ret some(ast::def_self(local_def(it.id)));
757757
}
758+
if ns == ns_type { ret lookup_in_ty_params(name, ty_params); }
758759
}
759760
ast::item_tag(_, ty_params) {
760761
if ns == ns_type { ret lookup_in_ty_params(name, ty_params); }

src/comp/middle/trans.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4353,15 +4353,19 @@ fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg,
43534353
// way.
43544354
let arg_n = 2u;
43554355
alt ty_self {
4356-
obj_self(tt) | impl_self(tt) { cx.llself = some({v: cx.llenv, t: tt}); }
4357-
no_self. {
4358-
let i = 0u;
4359-
for tp: ast::ty_param in ty_params {
4356+
obj_self(tt) | impl_self(tt) {
4357+
cx.llself = some({v: cx.llenv, t: tt});
4358+
}
4359+
no_self. {}
4360+
}
4361+
alt ty_self {
4362+
obj_self(_) {}
4363+
_ {
4364+
for tp in ty_params {
43604365
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
43614366
assert (llarg as int != 0);
43624367
cx.lltydescs += [llarg];
43634368
arg_n += 1u;
4364-
i += 1u;
43654369
}
43664370
}
43674371
}
@@ -4659,14 +4663,14 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
46594663
}
46604664

46614665
fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
4662-
id: ast::node_id) {
4666+
id: ast::node_id, tps: [ast::ty_param]) {
46634667
let sub_cx = extend_path(cx, name);
46644668
for m in methods {
46654669
alt cx.ccx.item_ids.find(m.node.id) {
46664670
some(llfn) {
46674671
trans_fn(extend_path(sub_cx, m.node.ident), m.span, m.node.meth,
46684672
llfn, impl_self(ty::node_id_to_monotype(cx.ccx.tcx, id)),
4669-
[], m.node.id);
4673+
tps + m.node.tps, m.node.id);
46704674
}
46714675
}
46724676
}
@@ -4980,7 +4984,9 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
49804984
with *extend_path(cx, item.ident)};
49814985
trans_obj(sub_cx, item.span, ob, ctor_id, tps);
49824986
}
4983-
ast::item_impl(_, _, ms) { trans_impl(cx, item.ident, ms, item.id); }
4987+
ast::item_impl(tps, _, ms) {
4988+
trans_impl(cx, item.ident, ms, item.id, tps);
4989+
}
49844990
ast::item_res(dtor, dtor_id, tps, ctor_id) {
49854991
trans_res_ctor(cx, item.span, dtor, ctor_id, tps);
49864992

@@ -5304,11 +5310,11 @@ fn collect_item_2(ccx: @crate_ctxt, i: @ast::item, &&pt: [str],
53045310
ccx.obj_methods.insert(m.node.id, ());
53055311
}
53065312
}
5307-
ast::item_impl(_, _, methods) {
5313+
ast::item_impl(tps, _, methods) {
53085314
let name = ccx.names.next(i.ident);
53095315
for m in methods {
53105316
register_fn(ccx, i.span, pt + [name, m.node.ident],
5311-
"impl_method", [], m.node.id);
5317+
"impl_method", tps + m.node.tps, m.node.id);
53125318
}
53135319
}
53145320
ast::item_res(_, dtor_id, tps, ctor_id) {

src/comp/middle/typeck.rs

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -962,8 +962,7 @@ mod writeback {
962962
typ) {
963963
fix_ok(new_type) { ret some(new_type); }
964964
fix_err(vid) {
965-
fcx.ccx.tcx.sess.span_err(sp,
966-
"cannot determine a type \
965+
fcx.ccx.tcx.sess.span_err(sp, "cannot determine a type \
967966
for this expression");
968967
ret none;
969968
}
@@ -1461,6 +1460,42 @@ fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool {
14611460
ret check_expr_with_unifier(fcx, expr, demand::simple, expected);
14621461
}
14631462

1463+
// FIXME[impl] notice/resolve conflicts
1464+
fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
1465+
name: ast::ident, ty: ty::t)
1466+
-> option::t<{method: @ast::method, ids: [int]}> {
1467+
let result = none;
1468+
std::list::iter(isc) {|impls|
1469+
for im in *impls {
1470+
alt im.node {
1471+
ast::item_impl(tps, slf, mthds) {
1472+
let self_ty = ast_ty_to_ty_crate(fcx.ccx, slf);
1473+
let tp_count = vec::len(tps);
1474+
let {ids, ty: self_ty} = if tp_count > 0u {
1475+
bind_params_in_type(ast_util::dummy_sp(), fcx.ccx.tcx,
1476+
bind next_ty_var_id(fcx), self_ty,
1477+
tp_count)
1478+
} else { {ids: [], ty: self_ty} };
1479+
// FIXME[impl] Don't unify in the current fcx, use
1480+
// scratch context
1481+
alt unify::unify(fcx, ty, self_ty) {
1482+
ures_ok(_) {
1483+
for m in mthds {
1484+
if m.node.ident == name {
1485+
result = some({method: m, ids: ids});
1486+
ret;
1487+
}
1488+
}
1489+
}
1490+
_ {}
1491+
}
1492+
}
1493+
}
1494+
}
1495+
}
1496+
result
1497+
}
1498+
14641499
fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
14651500
expected: ty::t) -> bool {
14661501
//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,
20892124
}
20902125
}
20912126
ast::expr_field(base, field) {
2092-
// FIXME proper type compare, notice conflicts
2093-
fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
2094-
name: ast::ident, ty: ty::t)
2095-
-> option::t<@ast::method> {
2096-
let result = none;
2097-
std::list::iter(isc) {|impls|
2098-
for im in *impls {
2099-
alt im.node {
2100-
ast::item_impl(_, slf, mthds) {
2101-
let self_ty = ast_ty_to_ty_crate(fcx.ccx, slf);
2102-
alt unify::unify(fcx, ty, self_ty) {
2103-
ures_ok(_) {}
2104-
_ { cont; }
2105-
}
2106-
for m in mthds {
2107-
if m.node.ident == name {
2108-
result = some(m);
2109-
ret;
2110-
}
2111-
}
2112-
}
2113-
}
2114-
}
2115-
}
2116-
result
2117-
}
2118-
21192127
bot |= check_expr(fcx, base);
21202128
let base_t = expr_ty(tcx, base);
21212129
let iscope = fcx.ccx.impl_map.get(expr.id);
21222130
alt lookup_method(fcx, iscope, field, base_t) {
2123-
some(method) {
2124-
let mt = ty_of_method(fcx.ccx.tcx, m_check, method);
2131+
some({method, ids}) {
2132+
let mt = ty_of_method(fcx.ccx.tcx, m_check, method), ids = ids;
21252133
let fty = ty::mk_fn(fcx.ccx.tcx, mt.proto, mt.inputs,
21262134
mt.output, mt.cf, mt.constrs);
2127-
write::ty_only_fixup(fcx, id, fty);
2135+
let tp_count = vec::len(method.node.tps);
2136+
if tp_count > 0u {
2137+
let b = bind_params_in_type(expr.span, tcx,
2138+
bind next_ty_var_id(fcx),
2139+
fty, tp_count);
2140+
ids += b.ids;
2141+
fty = b.ty;
2142+
}
2143+
let substs = vec::map({|id| ty::mk_var(tcx, id)}, ids);
2144+
write::ty_fixup(fcx, id, {substs: some(substs), ty: fty});
21282145
fcx.ccx.method_map.insert(id, local_def(method.node.id));
21292146
}
21302147
_ {

src/comp/syntax/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ tag ret_style {
423423

424424
type _fn = {decl: fn_decl, proto: proto, body: blk};
425425

426-
type method_ = {ident: ident, meth: _fn, id: node_id};
426+
type method_ = {ident: ident, meth: _fn, id: node_id, tps: [ty_param]};
427427

428428
type method = spanned<method_>;
429429

src/comp/syntax/fold.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
246246
}
247247

248248
fn noop_fold_method(m: method_, fld: ast_fold) -> method_ {
249-
ret {ident: fld.fold_ident(m.ident), meth: fld.fold_fn(m.meth), id: m.id};
249+
ret {ident: fld.fold_ident(m.ident), meth: fld.fold_fn(m.meth)
250+
with m};
250251
}
251252

252253

src/comp/syntax/parse/parser.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr {
854854
while p.peek() != token::RBRACE {
855855
if eat_word(p, "with") {
856856
inner_obj = some(parse_expr(p));
857-
} else { meths += [parse_method(p)]; }
857+
} else { meths += [parse_method(p, false)]; }
858858
}
859859
hi = p.get_hi_pos();
860860
expect(p, token::RBRACE);
@@ -1832,12 +1832,13 @@ fn parse_anon_obj_field(p: parser) -> ast::anon_obj_field {
18321832
ret {mut: mut, ty: ty, expr: expr, ident: ident, id: p.get_id()};
18331833
}
18341834

1835-
fn parse_method(p: parser) -> @ast::method {
1835+
fn parse_method(p: parser, allow_tps: bool) -> @ast::method {
18361836
let lo = p.get_lo_pos();
18371837
let proto = parse_method_proto(p);
18381838
let ident = parse_value_ident(p);
1839+
let tps = allow_tps ? parse_ty_params(p) : [];
18391840
let f = parse_fn(p, proto, ast::impure_fn, ast::il_normal);
1840-
let meth = {ident: ident, meth: f, id: p.get_id()};
1841+
let meth = {ident: ident, meth: f, id: p.get_id(), tps: tps};
18411842
ret @spanned(lo, f.body.span.hi, meth);
18421843
}
18431844

@@ -1850,7 +1851,7 @@ fn parse_item_obj(p: parser, attrs: [ast::attribute]) -> @ast::item {
18501851
parse_obj_field, p);
18511852
let meths: [@ast::method] = [];
18521853
expect(p, token::LBRACE);
1853-
while p.peek() != token::RBRACE { meths += [parse_method(p)]; }
1854+
while p.peek() != token::RBRACE { meths += [parse_method(p, false)]; }
18541855
let hi = p.get_hi_pos();
18551856
expect(p, token::RBRACE);
18561857
let ob: ast::_obj = {fields: fields.node, methods: meths};
@@ -1864,7 +1865,7 @@ fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item {
18641865
expect_word(p, "for");
18651866
let ty = parse_ty(p, false), meths = [];
18661867
expect(p, token::LBRACE);
1867-
while !eat(p, token::RBRACE) { meths += [parse_method(p)]; }
1868+
while !eat(p, token::RBRACE) { meths += [parse_method(p, true)]; }
18681869
ret mk_item(p, lo, p.get_last_hi_pos(), ident,
18691870
ast::item_impl(tps, ty, meths), attrs);
18701871
}

src/comp/syntax/visit.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,15 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
101101
item_obj(ob, _, _) {
102102
for f: obj_field in ob.fields { v.visit_ty(f.ty, e, v); }
103103
for m: @method in ob.methods {
104-
v.visit_fn(m.node.meth, [], m.span, some(m.node.ident), m.node.id,
105-
e, v);
104+
v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident),
105+
m.node.id, e, v);
106106
}
107107
}
108108
item_impl(_, ty, methods) {
109109
visit_ty(ty, e, v);
110110
for m in methods {
111-
v.visit_fn(m.node.meth, [], m.span, some(m.node.ident), m.node.id,
112-
e, v);
111+
v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident),
112+
m.node.id, e, v);
113113
}
114114
}
115115
}
@@ -321,8 +321,8 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
321321
some(ex) { v.visit_expr(ex, e, v); }
322322
}
323323
for m: @method in anon_obj.methods {
324-
v.visit_fn(m.node.meth, [], m.span, some(m.node.ident), m.node.id,
325-
e, v);
324+
v.visit_fn(m.node.meth, m.node.tps, m.span, some(m.node.ident),
325+
m.node.id, e, v);
326326
}
327327
}
328328
expr_mac(mac) { visit_mac(mac, e, v); }

0 commit comments

Comments
 (0)