diff options
| author | Marijn Haverbeke <marijnh@gmail.com> | 2012-01-25 16:44:51 +0100 |
|---|---|---|
| committer | Marijn Haverbeke <marijnh@gmail.com> | 2012-01-25 20:47:11 +0100 |
| commit | 2d4d8e8bdbe2c6d0656c4887ad8ccadcb8a39966 (patch) | |
| tree | 80aa0c77bcad42213b2db6d2f3c301f97f52e110 /src/comp | |
| parent | 76aabbe99d598dc42e8e3723d98516422bd26d33 (diff) | |
| download | rust-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.rs | 16 | ||||
| -rw-r--r-- | src/comp/middle/resolve.rs | 2 | ||||
| -rw-r--r-- | src/comp/middle/trans.rs | 2 | ||||
| -rw-r--r-- | src/comp/middle/ty.rs | 35 | ||||
| -rw-r--r-- | src/comp/middle/typeck.rs | 109 | ||||
| -rw-r--r-- | src/comp/syntax/parse/parser.rs | 5 | ||||
| -rw-r--r-- | src/comp/syntax/print/pprust.rs | 3 |
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); |
