Skip to content

Commit 3c4baf6

Browse files
committed
better support for classes with polymorphic methods
1 parent 7213274 commit 3c4baf6

File tree

8 files changed

+37
-70
lines changed

8 files changed

+37
-70
lines changed

src/rustc/metadata/encoder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
664664
ebml_w.start_tag(tag_item_iface_method);
665665
encode_family(ebml_w, purity_fn_family(m.decl.purity));
666666
encode_name(ebml_w, m.ident);
667-
encode_type_param_bounds(ebml_w, ecx, tps + m.tps);
667+
encode_type_param_bounds(ebml_w, ecx, m.tps);
668668
encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id));
669669
encode_def_id(ebml_w, local_def(m.id));
670670
ebml_w.end_tag();

src/rustc/middle/kind.rs

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -254,29 +254,16 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
254254
expr_field(base, _, _) {
255255
alt cx.method_map.get(e.id) {
256256
typeck::method_static(did) {
257-
/*
258-
If this is a class method, we want to use the
259-
class bounds plus the method bounds -- otherwise the
260-
indices come out wrong. So we check base's type...
261-
*/
262-
let mut bounds = ty::lookup_item_type(cx.tcx, did).bounds;
263-
alt ty::get(ty::node_id_to_type(cx.tcx, base.id)).struct {
264-
ty::ty_class(parent_id, ts) {
265-
/* ...and if it has a class type, prepend the
266-
class bounds onto the method bounds */
267-
/* n.b. this code is very likely sketchy --
268-
currently, class-impl-very-parameterized-iface
269-
fails here and is thus xfailed */
270-
bounds =
271-
@(*ty::lookup_item_type(cx.tcx, parent_id).bounds
272-
+ *bounds);
273-
}
274-
_ { }
275-
}
276-
bounds
257+
// n.b.: When we encode class/impl methods, the bounds
258+
// that we encode include both the class/impl bounds
259+
// and then the method bounds themselves...
260+
ty::lookup_item_type(cx.tcx, did).bounds
277261
}
278262
typeck::method_param(ifce_id, n_mth, _, _) |
279263
typeck::method_iface(ifce_id, n_mth) {
264+
// ...iface methods bounds, in contrast, include only the
265+
// method bounds, so we must preprend the tps from the
266+
// iface itself. This ought to be harmonized.
280267
let ifce_bounds =
281268
ty::lookup_item_type(cx.tcx, ifce_id).bounds;
282269
let mth = ty::iface_methods(cx.tcx, ifce_id)[n_mth];

src/rustc/middle/typeck/check/method.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ enum lookup = {
1818
impl methods for lookup {
1919
// Entrypoint:
2020
fn method() -> option<method_origin> {
21+
#debug["method lookup(m_name=%s, self_ty=%s)",
22+
self.m_name, self.fcx.infcx.ty_to_str(self.self_ty)];
23+
2124
// First, see whether this is an interface-bounded parameter
2225
let pass1 = alt ty::get(self.self_ty).struct {
2326
ty::ty_param(n, did) {
@@ -288,6 +291,11 @@ impl methods for lookup {
288291

289292
let tcx = self.fcx.ccx.tcx;
290293

294+
#debug["write_mty_from_fty(n_tps_m=%u, fty=%s, origin=%?)",
295+
n_tps_m,
296+
self.fcx.infcx.ty_to_str(fty),
297+
origin];
298+
291299
// Here I will use the "c_" prefix to refer to the method's
292300
// owner. You can read it as class, but it may also be an iface.
293301

src/rustc/middle/typeck/collect.rs

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -228,17 +228,15 @@ fn check_methods_against_iface(ccx: @crate_ctxt,
228228
rp: ast::region_param,
229229
selfty: ty::t,
230230
a_ifacety: @ast::iface_ref,
231-
ms: [@ast::method]) {
231+
ms: [converted_method]) {
232232

233233
let tcx = ccx.tcx;
234-
let i_bounds = ty_param_bounds(ccx, tps);
235-
let my_methods = convert_methods(ccx, ms, rp, i_bounds, selfty);
236234
let (did, tpt) = instantiate_iface_ref(ccx, a_ifacety, rp);
237235
if did.crate == ast::local_crate {
238236
ensure_iface_methods(ccx, did.node);
239237
}
240238
for vec::each(*ty::iface_methods(tcx, did)) {|if_m|
241-
alt vec::find(my_methods, {|m| if_m.ident == m.mty.ident}) {
239+
alt vec::find(ms, {|m| if_m.ident == m.mty.ident}) {
242240
some({mty: m, id, span}) {
243241
if m.purity != if_m.purity {
244242
ccx.tcx.sess.span_err(
@@ -274,12 +272,13 @@ fn convert_class_item(ccx: @crate_ctxt,
274272
ccx.tcx.tcache.insert(local_def(v.id), {bounds: bounds, rp: rp, ty: tt});
275273
}
276274

275+
type converted_method = {mty: ty::method, id: ast::node_id, span: span};
276+
277277
fn convert_methods(ccx: @crate_ctxt,
278278
ms: [@ast::method],
279279
rp: ast::region_param,
280-
i_bounds: @[ty::param_bounds],
281-
self_ty: ty::t)
282-
-> [{mty: ty::method, id: ast::node_id, span: span}] {
280+
rcvr_bounds: @[ty::param_bounds],
281+
self_ty: ty::t) -> [converted_method] {
283282

284283
let tcx = ccx.tcx;
285284
vec::map(ms) { |m|
@@ -289,9 +288,10 @@ fn convert_methods(ccx: @crate_ctxt,
289288
let fty = ty::mk_fn(tcx, mty.fty);
290289
tcx.tcache.insert(
291290
local_def(m.id),
292-
// n.b. This code is kind of sketchy (concat'ing i_bounds
293-
// with bounds), but removing *i_bounds breaks other stuff
294-
{bounds: @(*i_bounds + *bounds), rp: rp, ty: fty});
291+
292+
// n.b.: the type of a method is parameterized by both
293+
// the tps on the receiver and those on the method itself
294+
{bounds: @(*rcvr_bounds + *bounds), rp: rp, ty: fty});
295295
write_ty_to_tcx(tcx, m.id, fty);
296296
{mty: mty, id: m.id, span: m.span}
297297
}
@@ -316,19 +316,10 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
316316
{bounds: i_bounds,
317317
rp: rp,
318318
ty: selfty});
319-
alt ifce {
320-
some(t) {
321-
check_methods_against_iface(
322-
ccx, tps, rp,
323-
selfty, t, ms);
324-
}
325-
_ {
326-
// Still have to do this to write method types
327-
// into the table
328-
convert_methods(
329-
ccx, ms, rp,
330-
i_bounds, selfty);
331-
}
319+
320+
let cms = convert_methods(ccx, ms, rp, i_bounds, selfty);
321+
for ifce.each { |t|
322+
check_methods_against_iface(ccx, tps, rp, selfty, t, cms);
332323
}
333324
}
334325
ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
@@ -412,23 +403,11 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
412403
for fields.each {|f|
413404
convert_class_item(ccx, rp, tpt.bounds, f);
414405
}
415-
// The selfty is just the class type
416-
let {bounds:_, substs} = mk_substs(ccx, tps, rp);
406+
let {bounds, substs} = mk_substs(ccx, tps, rp);
417407
let selfty = ty::mk_class(tcx, local_def(it.id), substs);
418-
// Need to convert all methods so we can check internal
419-
// references to private methods
420-
421-
// NDM to TJC---I think we ought to be using bounds here, not @[].
422-
// But doing so causes errors later on.
423-
convert_methods(ccx, methods, rp, @[], selfty);
424-
425-
/*
426-
Finally, check that the class really implements the ifaces
427-
that it claims to implement.
428-
*/
408+
let cms = convert_methods(ccx, methods, rp, bounds, selfty);
429409
for ifaces.each { |ifce|
430-
check_methods_against_iface(ccx, tps, rp, selfty,
431-
ifce, methods);
410+
check_methods_against_iface(ccx, tps, rp, selfty, ifce, cms);
432411

433412
// FIXME #2434---this is somewhat bogus, but it seems that
434413
// the id of iface_ref is also the id of the impl, and so

src/test/run-pass/borrowck-preserve-box-in-pat.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// xfail-test (still buggy)
21
// xfail-fast (compile-flags unsupported on windows)
32
// compile-flags:--borrowck=err
43
// exec-env:RUST_POISON_ON_FREE=1

src/test/run-pass/class-impl-very-parameterized-iface.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// xfail-test
2-
// xfail-fast
31
use std;
42
import std::map::*;
53

@@ -59,7 +57,7 @@ class cat<T: copy> implements map<int, T> {
5957
}
6058
else { none }
6159
}
62-
60+
6361
fn remove(&&k:int) -> option<T> {
6462
alt self.find(k) {
6563
some(x) {
@@ -76,7 +74,7 @@ class cat<T: copy> implements map<int, T> {
7674
n -= 1;
7775
}
7876
}
79-
77+
8078
fn each_key(&&f: fn(&&int) -> bool) {
8179
for self.each {|k, _v| if !f(k) { break; } cont;};
8280
}
@@ -88,11 +86,11 @@ class cat<T: copy> implements map<int, T> {
8886

8987
fn main() {
9088
let nyan : cat<str> = cat(0, 2, "nyan");
91-
uint::range(1u, 5u) {|_i| nyan.speak(); }
89+
for uint::range(1u, 5u) {|_i| nyan.speak(); }
9290
assert(nyan.find(1) == some("nyan"));
9391
assert(nyan.find(10) == none);
9492
let spotty : cat<cat_type> = cat(2, 57, tuxedo);
95-
uint::range(0u, 6u) {|_i| spotty.speak(); }
93+
for uint::range(0u, 6u) {|_i| spotty.speak(); }
9694
assert(spotty.size() == 8u);
9795
assert(spotty.contains_key(2));
9896
assert(spotty.get(3) == tuxedo);

src/test/run-pass/class-poly-methods-cross-crate.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// xfail-test
2-
31
// xfail-fast
42
// aux-build:cci_class_6.rs
53
use cci_class_6;

src/test/run-pass/class-typarams.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// xfail-test
2-
// needs metadata encoding on Windows
31
class cat<U> {
42
priv {
53
let mut meows : uint;

0 commit comments

Comments
 (0)