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:
parent
301f6aaa31
commit
3243144046
@ -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)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user