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

View file

@ -16,9 +16,7 @@ fn main() {
auto my_a = a();
// An anonymous object that overloads the 'foo' method. Adding
// support for this is issue #543 (making this work in the
// presence of self-calls is the tricky part).
// An anonymous object that overloads the 'foo' method.
auto my_b = obj() {
fn foo() -> int {
ret 3;
@ -27,15 +25,7 @@ fn main() {
with my_a
};
// FIXME: raises a valgrind error (issue #543).
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);
}