Fix a bug that was interfering with method overriding. Issue #543.

Previously, we were creating both a normal vtable entry and a
forwarding function for overriding methods, when they should have just
gotten a vtable entry.  This patch fixes that.
This commit is contained in:
Lindsey Kuper 2011-07-07 17:10:17 -07:00
parent 301f6aaa31
commit 3243144046
2 changed files with 37 additions and 34 deletions

View File

@ -8152,34 +8152,47 @@ fn create_vtbl(@local_ctxt cx, &span sp, TypeRef llself_ty, ty::t self_ty,
} }
} }
// Now, filter out any methods that are being replaced. // Now, filter out any methods that we don't need forwarding slots
fn filtering_fn(&vtbl_mthd m, vec[vtbl_mthd] addtl_meths) -> // for, because they're being replaced.
option::t[vtbl_mthd] { fn filtering_fn(@local_ctxt cx, &vtbl_mthd m,
(@ast::method)[] addtl_meths)
-> option::t[vtbl_mthd] {
let option::t[vtbl_mthd] rslt; alt (m) {
if (std::vec::member[vtbl_mthd](m, addtl_meths)) { case (fwding_mthd(?fm)) {
rslt = none; // Since fm is a fwding_mthd, and we're checking to
} else { // see if it's in addtl_meths (which only contains
rslt = some(m); // normal_mthds), we can't just check if fm is a
} // member of addtl_meths. Instead, we have to go
ret rslt; // through addtl_meths and see if there's some method
} // in it that has the same name as fm.
// NB: addtl_meths is just like ob.methods except that it's of // FIXME (part of #543): We're only checking names
// type vec[vtbl_mthd], not vec[@ast::method]. // here. If a method is replacing another, it also
let vec[vtbl_mthd] addtl_meths = []; // needs to have the same type, but this should
for (@ast::method m in ob.methods) { // probably be enforced in typechecking.
addtl_meths += [normal_mthd(m)]; for (@ast::method am in addtl_meths) {
if (str::eq(am.node.ident, fm.ident)) {
ret none;
} }
auto f = bind filtering_fn(_, addtl_meths); }
ret some(fwding_mthd(fm));
// Filter out any methods that we don't need forwarding slots for }
// (namely, those that are being replaced). case (normal_mthd(_)) {
// Should never happen.
cx.ccx.sess.bug("create_vtbl(): shouldn't be any"
+ " normal_mthds in meths here");
}
}
}
auto f = bind filtering_fn(cx, _, ob.methods);
meths = std::vec::filter_map[vtbl_mthd, vtbl_mthd](f, meths); meths = std::vec::filter_map[vtbl_mthd, vtbl_mthd](f, meths);
// And now add the additional ones (both replacements and entirely // And now add the additional ones (both replacements and entirely
// new ones). // new ones). These'll just be normal methods.
meths += addtl_meths; for (@ast::method m in ob.methods) {
meths += [normal_mthd(m)];
}
} }
} }

View File

@ -16,9 +16,7 @@ fn main() {
auto my_a = a(); auto my_a = a();
// An anonymous object that overloads the 'foo' method. Adding // An anonymous object that overloads the 'foo' method.
// support for this is issue #543 (making this work in the
// presence of self-calls is the tricky part).
auto my_b = obj() { auto my_b = obj() {
fn foo() -> int { fn foo() -> int {
ret 3; ret 3;
@ -27,15 +25,7 @@ fn main() {
with my_a with my_a
}; };
// FIXME: raises a valgrind error (issue #543).
assert (my_b.foo() == 3); assert (my_b.foo() == 3);
// The tricky part -- have to be sure to tie the knot in the right
// place, so that bar() knows about the new foo().
// Right now, this just fails with "unknown method 'bar' of obj",
// but that's the easier of our worries; that'll be fixed when
// issue #539 is fixed. The bigger problem will be when we do
// 'fall through' to bar() on the original object -- then we have
// to be sure that self refers to the extended object.
assert (my_b.bar() == 3); assert (my_b.bar() == 3);
} }