Skip to content

Commit 2d4d8e8

Browse files
committed
Implement implicit self type parameters for ifaces
Closes #1661
1 parent 76aabbe commit 2d4d8e8

File tree

8 files changed

+102
-72
lines changed

8 files changed

+102
-72
lines changed

src/comp/metadata/decoder.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,15 @@ fn item_impl_iface(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
128128
result
129129
}
130130

131-
fn item_ty_param_bounds(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
132-
-> @[ty::param_bounds] {
133-
let bounds = [];
131+
fn item_ty_param_bounds(item: ebml::doc, tcx: ty::ctxt, cdata: cmd,
132+
skip: bool) -> @[ty::param_bounds] {
133+
let bounds = [], skip = skip;
134134
ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds) {|p|
135135
let bd = parse_bounds_data(p.data, p.start, cdata.cnum, tcx, {|did|
136136
translate_def_id(cdata, did)
137137
});
138-
bounds += [bd];
138+
if skip { skip = false; }
139+
else { bounds += [bd]; }
139140
}
140141
@bounds
141142
}
@@ -218,8 +219,9 @@ fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
218219
-> ty::ty_param_bounds_and_ty {
219220
let item = lookup_item(id, cdata.data);
220221
let t = item_type(item, tcx, cdata);
221-
let tp_bounds = if family_has_type_params(item_family(item)) {
222-
item_ty_param_bounds(item, tcx, cdata)
222+
let family = item_family(item);
223+
let tp_bounds = if family_has_type_params(family) {
224+
item_ty_param_bounds(item, tcx, cdata, family == ('I' as u8))
223225
} else { @[] };
224226
ret {bounds: tp_bounds, ty: t};
225227
}
@@ -302,7 +304,7 @@ fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
302304
let data = cdata.data;
303305
let item = lookup_item(id, data), result = [];
304306
ebml::tagged_docs(item, tag_item_method) {|mth|
305-
let bounds = item_ty_param_bounds(mth, tcx, cdata);
307+
let bounds = item_ty_param_bounds(mth, tcx, cdata, false);
306308
let name = item_name(mth);
307309
let ty = doc_type(mth, tcx, cdata);
308310
let fty = alt ty::struct(tcx, ty) { ty::ty_fn(f) { f } };

src/comp/middle/resolve.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param])
10141014
} { ret some(ast::def_ty_param(local_def(tp.id), n)); }
10151015
n += 1u;
10161016
}
1017-
ret none::<def>;
1017+
ret none;
10181018
}
10191019

10201020
fn lookup_in_pat(e: env, name: ident, pat: @ast::pat) -> option::t<def_id> {

src/comp/middle/trans.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,7 @@ fn linearize_ty_params(cx: @block_ctxt, t: ty::t) ->
892892
}
893893
let x = @{cx: cx, mutable vals: param_vals, mutable defs: param_defs};
894894
let f = bind linearizer(x, _);
895-
ty::walk_ty(bcx_tcx(cx), f, t);
895+
ty::walk_ty(bcx_tcx(cx), t, f);
896896
ret {params: x.defs, descs: x.vals};
897897
}
898898

src/comp/middle/ty.rs

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -673,41 +673,37 @@ pure fn ty_name(cx: ctxt, typ: t) -> option::t<@str> {
673673
}
674674
}
675675

676-
677-
// Type folds
678-
type ty_walk = fn@(t);
679-
680-
fn walk_ty(cx: ctxt, walker: ty_walk, ty: t) {
676+
fn walk_ty(cx: ctxt, ty: t, walker: fn(t)) {
681677
alt struct(cx, ty) {
682678
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
683679
ty_str | ty_send_type | ty_type | ty_native(_) |
684680
ty_opaque_closure_ptr(_) {
685681
/* no-op */
686682
}
687-
ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, walker, tm.ty); }
683+
ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, tm.ty, walker); }
688684
ty_enum(_, subtys) | ty_iface(_, subtys) {
689-
for subty: t in subtys { walk_ty(cx, walker, subty); }
685+
for subty: t in subtys { walk_ty(cx, subty, walker); }
690686
}
691687
ty_rec(fields) {
692-
for fl: field in fields { walk_ty(cx, walker, fl.mt.ty); }
688+
for fl: field in fields { walk_ty(cx, fl.mt.ty, walker); }
693689
}
694-
ty_tup(ts) { for tt in ts { walk_ty(cx, walker, tt); } }
690+
ty_tup(ts) { for tt in ts { walk_ty(cx, tt, walker); } }
695691
ty_fn(f) {
696-
for a: arg in f.inputs { walk_ty(cx, walker, a.ty); }
697-
walk_ty(cx, walker, f.output);
692+
for a: arg in f.inputs { walk_ty(cx, a.ty, walker); }
693+
walk_ty(cx, f.output, walker);
698694
}
699695
ty_native_fn(args, ret_ty) {
700-
for a: arg in args { walk_ty(cx, walker, a.ty); }
701-
walk_ty(cx, walker, ret_ty);
696+
for a: arg in args { walk_ty(cx, a.ty, walker); }
697+
walk_ty(cx, ret_ty, walker);
702698
}
703699
ty_res(_, sub, tps) {
704-
walk_ty(cx, walker, sub);
705-
for tp: t in tps { walk_ty(cx, walker, tp); }
700+
walk_ty(cx, sub, walker);
701+
for tp: t in tps { walk_ty(cx, tp, walker); }
706702
}
707-
ty_constr(sub, _) { walk_ty(cx, walker, sub); }
703+
ty_constr(sub, _) { walk_ty(cx, sub, walker); }
708704
ty_var(_) {/* no-op */ }
709705
ty_param(_, _) {/* no-op */ }
710-
ty_uniq(tm) { walk_ty(cx, walker, tm.ty); }
706+
ty_uniq(tm) { walk_ty(cx, tm.ty, walker); }
711707
}
712708
walker(ty);
713709
}
@@ -1273,7 +1269,7 @@ fn vars_in_type(cx: ctxt, ty: t) -> [int] {
12731269
alt struct(cx, ty) { ty_var(v) { *vars += [v]; } _ { } }
12741270
}
12751271
let rslt: @mutable [int] = @mutable [];
1276-
walk_ty(cx, bind collect_var(cx, rslt, _), ty);
1272+
walk_ty(cx, ty) {|t| collect_var(cx, rslt, t)}
12771273
// Works because of a "convenient" bug that lets us
12781274
// return a mutable vec as if it's immutable
12791275
ret *rslt;
@@ -1529,7 +1525,7 @@ fn count_ty_params(cx: ctxt, ty: t) -> uint {
15291525
}
15301526
let param_indices: @mutable [uint] = @mutable [];
15311527
let f = bind counter(cx, param_indices, _);
1532-
walk_ty(cx, f, ty);
1528+
walk_ty(cx, ty, f);
15331529
ret vec::len::<uint>(*param_indices);
15341530
}
15351531

@@ -2695,7 +2691,6 @@ fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
26952691
if did.crate == ast::local_crate {
26962692
// The item is in this crate. The caller should have added it to the
26972693
// type cache already; we simply return it.
2698-
26992694
ret cx.tcache.get(did);
27002695
}
27012696
alt cx.tcache.find(did) {

src/comp/middle/typeck.rs

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -415,16 +415,15 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
415415
ret tpt;
416416
}
417417
ast::item_iface(tps, ms) {
418-
let {bounds, params} = mk_ty_params(tcx, tps);
419-
let t = ty::mk_named(tcx, ty::mk_iface(tcx, local_def(it.id),
420-
params),
418+
let s_tp = vec::len(tps) - 1u;
419+
tcx.ty_param_bounds.insert(tps[s_tp].id, @[]);
420+
let {bounds, params} = mk_ty_params(tcx, vec::slice(tps, 0u, s_tp));
421+
let t = ty::mk_named(tcx, ty::mk_iface(tcx, local_def(it.id), params),
421422
@it.ident);
422423
let tpt = {bounds: bounds, ty: t};
423424
tcx.tcache.insert(local_def(it.id), tpt);
424425
ret tpt;
425426
}
426-
ast::item_impl(_, _, _, _) | ast::item_mod(_) |
427-
ast::item_native_mod(_) { fail; }
428427
}
429428
}
430429
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])
604603
}
605604

606605
fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
607-
impl_tps: uint, if_m: ty::method, substs: [ty::t]) {
606+
impl_tps: uint, if_m: ty::method, substs: [ty::t])
607+
-> ty::t {
608608
if impl_m.tps != if_m.tps {
609609
tcx.sess.span_err(sp, "method `" + if_m.ident +
610610
"` has an incompatible set of type parameters");
611+
ty::mk_fn(tcx, impl_m.fty)
611612
} else {
612-
let impl_fty = ty::mk_fn(tcx, impl_m.fty);
613+
let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f|
614+
alt ty::struct(tcx, f.ty) {
615+
ty::ty_param(0u, _) { {mode: ast::by_ref with i} }
616+
_ { i }
617+
}
618+
});
619+
let impl_fty = ty::mk_fn(tcx, {inputs: auto_modes with impl_m.fty});
613620
// Add dummy substs for the parameters of the impl method
614621
let substs = substs + vec::init_fn(vec::len(*if_m.tps), {|i|
615622
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,
621628
tcx.sess.span_err(sp, "method `" + if_m.ident +
622629
"` has an incompatible type: " +
623630
ty::type_err_to_str(err));
631+
impl_fty
624632
}
625-
_ {}
633+
ty::unify::ures_ok(tp) { tp }
626634
}
627635
}
628636
}
@@ -690,15 +698,15 @@ mod collect {
690698
for m in ms {
691699
let bounds = ty_param_bounds(cx.tcx, m_collect, m.tps);
692700
let mty = ty_of_method(cx.tcx, m_collect, m);
693-
my_methods += [mty];
701+
my_methods += [{mty: mty, id: m.id}];
694702
let fty = ty::mk_fn(cx.tcx, mty.fty);
695703
cx.tcx.tcache.insert(local_def(m.id),
696704
{bounds: @(*i_bounds + *bounds),
697705
ty: fty});
698706
write::ty_only(cx.tcx, m.id, fty);
699707
}
700-
write::ty_only(cx.tcx, it.id, ast_ty_to_ty(cx.tcx, m_collect,
701-
selfty));
708+
let selfty = ast_ty_to_ty(cx.tcx, m_collect, selfty);
709+
write::ty_only(cx.tcx, it.id, selfty);
702710
alt ifce {
703711
some(t) {
704712
let iface_ty = ast_ty_to_ty(cx.tcx, m_collect, t);
@@ -708,10 +716,18 @@ mod collect {
708716
ty::ty_iface(did, tys) {
709717
for if_m in *ty::iface_methods(cx.tcx, did) {
710718
alt vec::find(my_methods,
711-
{|m| if_m.ident == m.ident}) {
712-
some(m) {
713-
compare_impl_method(cx.tcx, t.span, m,
714-
vec::len(tps), if_m, tys);
719+
{|m| if_m.ident == m.mty.ident}) {
720+
some({mty: m, id}) {
721+
let mt = compare_impl_method(
722+
cx.tcx, t.span, m, vec::len(tps), if_m,
723+
tys + [selfty]);
724+
let old = cx.tcx.tcache.get(local_def(id));
725+
if old.ty != mt {
726+
cx.tcx.tcache.insert(local_def(id),
727+
{bounds: old.bounds,
728+
ty: mt});
729+
write::ty_only(cx.tcx, id, mt);
730+
}
715731
}
716732
none {
717733
cx.tcx.sess.span_err(t.span, "missing method `" +
@@ -1501,7 +1517,7 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
15011517
let m = ifce_methods[pos];
15021518
ret some({method_ty: ty::mk_fn(tcx, m.fty),
15031519
n_tps: vec::len(*m.tps),
1504-
substs: tps,
1520+
substs: tps + [ty],
15051521
origin: method_param(iid, pos, n, bound_n)});
15061522
}
15071523
_ {}
@@ -1519,7 +1535,7 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
15191535
if m.ident == name {
15201536
ret some({method_ty: ty::mk_fn(tcx, m.fty),
15211537
n_tps: vec::len(*m.tps),
1522-
substs: tps,
1538+
substs: tps + [ty::mk_int(tcx)],
15231539
origin: method_iface(i)});
15241540
}
15251541
i += 1u;
@@ -1528,17 +1544,6 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
15281544
_ {}
15291545
}
15301546

1531-
fn ty_from_did(tcx: ty::ctxt, did: ast::def_id) -> ty::t {
1532-
if did.crate == ast::local_crate {
1533-
alt tcx.items.get(did.node) {
1534-
ast_map::node_method(m) {
1535-
let mt = ty_of_method(tcx, m_check, m);
1536-
ty::mk_fn(tcx, mt.fty)
1537-
}
1538-
}
1539-
} else { csearch::get_type(tcx, did).ty }
1540-
}
1541-
15421547
let result = none;
15431548
std::list::iter(isc) {|impls|
15441549
if option::is_some(result) { ret; }
@@ -1557,7 +1562,7 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
15571562
sp, "multiple applicable methods in scope");
15581563
} else {
15591564
result = some({
1560-
method_ty: ty_from_did(tcx, m.did),
1565+
method_ty: ty::lookup_item_type(tcx, m.did).ty,
15611566
n_tps: m.n_tps,
15621567
substs: vars,
15631568
origin: method_static(m.did)
@@ -1812,16 +1817,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
18121817

18131818
check_binop_type_compat(fcx, expr.span, lhs_t, binop);
18141819

1815-
let t =
1816-
alt binop {
1817-
ast::eq { ty::mk_bool(tcx) }
1818-
ast::lt { ty::mk_bool(tcx) }
1819-
ast::le { ty::mk_bool(tcx) }
1820-
ast::ne { ty::mk_bool(tcx) }
1821-
ast::ge { ty::mk_bool(tcx) }
1822-
ast::gt { ty::mk_bool(tcx) }
1823-
_ { lhs_t }
1824-
};
1820+
let t = alt binop {
1821+
ast::eq | ast::lt | ast::le | ast::ne | ast::ge |
1822+
ast::gt { ty::mk_bool(tcx) }
1823+
_ { lhs_t }
1824+
};
18251825
write::ty_only_fixup(fcx, id, t);
18261826
}
18271827
ast::expr_unary(unop, oper) {
@@ -2915,9 +2915,38 @@ mod dict {
29152915
}
29162916
}
29172917
ast::expr_cast(src, _) {
2918+
// Ifaces that refer to a self type can not be cast to -- callers
2919+
// wouldn't know what self refers to.
2920+
fn type_refers_to_self(tcx: ty::ctxt, t: ty::t, s_param: uint)
2921+
-> bool {
2922+
let found = false;
2923+
if ty::type_contains_params(tcx, t) {
2924+
ty::walk_ty(tcx, t) {|t|
2925+
alt ty::struct(tcx, t) {
2926+
ty::ty_param(n, _) if n == s_param { found = true; }
2927+
_ {}
2928+
}
2929+
}
2930+
}
2931+
found
2932+
}
2933+
fn method_refers_to_self(tcx: ty::ctxt, m: ty::method,
2934+
s_param: uint) -> bool {
2935+
vec::any(m.fty.inputs, {|in|
2936+
type_refers_to_self(tcx, in.ty, s_param)
2937+
}) || type_refers_to_self(tcx, m.fty.output, s_param)
2938+
}
29182939
let target_ty = expr_ty(cx.tcx, ex);
29192940
alt ty::struct(cx.tcx, target_ty) {
2920-
ty::ty_iface(_, _) {
2941+
ty::ty_iface(id, tps) {
2942+
for m in *ty::iface_methods(cx.tcx, id) {
2943+
if method_refers_to_self(cx.tcx, m, vec::len(tps)) {
2944+
cx.tcx.sess.span_err(
2945+
ex.span, "can not cast to an iface type that \
2946+
refers to `self` " + m.ident);
2947+
break;
2948+
}
2949+
}
29212950
let impls = cx.impl_map.get(ex.id);
29222951
let dict = lookup_dict(fcx, impls, ex.span,
29232952
expr_ty(cx.tcx, src), target_ty);

src/comp/syntax/parse/parser.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,9 +1831,10 @@ fn parse_method(p: parser) -> @ast::method {
18311831

18321832
fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item {
18331833
let lo = p.last_span.lo, ident = parse_ident(p),
1834-
tps = parse_ty_params(p), meths = parse_ty_methods(p);
1834+
tps = parse_ty_params(p), meths = parse_ty_methods(p),
1835+
self_tp = {ident: "self", id: p.get_id(), bounds: @[]};
18351836
ret mk_item(p, lo, p.last_span.hi, ident,
1836-
ast::item_iface(tps, meths), attrs);
1837+
ast::item_iface(tps + [self_tp], meths), attrs);
18371838
}
18381839

18391840
// Parses three variants (with the initial params always optional):

src/comp/syntax/print/pprust.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,8 @@ fn print_item(s: ps, &&item: @ast::item) {
488488
ast::item_iface(tps, methods) {
489489
head(s, "iface");
490490
word(s.s, item.ident);
491-
print_type_params(s, tps);
491+
print_type_params(s, vec::slice(tps, 0u, vec::len(tps) - 1u));
492+
nbsp(s);
492493
bopen(s);
493494
for meth in methods { print_ty_method(s, meth); }
494495
bclose(s, item.span);

src/test/run-pass/iface-generic.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ impl of to_str for () {
1212
}
1313

1414
iface map<T> {
15+
fn iter(fn(T));
1516
fn map<U>(f: fn(T) -> U) -> [U];
1617
}
1718
impl <T> of map<T> for [T] {
19+
fn iter(_f: fn(T)) {}
1820
fn map<U>(f: fn(T) -> U) -> [U] {
1921
let r = [];
2022
for x in self { r += [f(x)]; }

0 commit comments

Comments
 (0)