Fix incorrect binding of classmethod when called on instance of subclass

This commit is contained in:
K. Lange 2021-04-02 12:25:07 +09:00
parent ea443f11df
commit dc361af48b
3 changed files with 17 additions and 2 deletions

View File

@ -910,6 +910,7 @@ KrkValue krk_callSimple(KrkValue value, int argCount, int isMethod) {
* Works for managed and native method calls. * Works for managed and native method calls.
*/ */
int krk_bindMethod(KrkClass * _class, KrkString * name) { int krk_bindMethod(KrkClass * _class, KrkString * name) {
KrkClass * originalClass = _class;
KrkValue method, out; KrkValue method, out;
while (_class) { while (_class) {
if (krk_tableGet_fast(&_class->methods, name, &method)) break; if (krk_tableGet_fast(&_class->methods, name, &method)) break;
@ -920,7 +921,7 @@ int krk_bindMethod(KrkClass * _class, KrkString * name) {
if (((KrkNative*)AS_OBJECT(method))->flags & KRK_NATIVE_FLAGS_IS_DYNAMIC_PROPERTY) { if (((KrkNative*)AS_OBJECT(method))->flags & KRK_NATIVE_FLAGS_IS_DYNAMIC_PROPERTY) {
out = AS_NATIVE(method)->function(1, (KrkValue[]){krk_peek(0)}, 0); out = AS_NATIVE(method)->function(1, (KrkValue[]){krk_peek(0)}, 0);
} else if (((KrkNative*)AS_OBJECT(method))->flags & KRK_NATIVE_FLAGS_IS_CLASS_METHOD) { } else if (((KrkNative*)AS_OBJECT(method))->flags & KRK_NATIVE_FLAGS_IS_CLASS_METHOD) {
out = OBJECT_VAL(krk_newBoundMethod(OBJECT_VAL(_class), AS_OBJECT(method))); out = OBJECT_VAL(krk_newBoundMethod(OBJECT_VAL(originalClass), AS_OBJECT(method)));
} else if (((KrkNative*)AS_OBJECT(method))->flags & KRK_NATIVE_FLAGS_IS_STATIC_METHOD) { } else if (((KrkNative*)AS_OBJECT(method))->flags & KRK_NATIVE_FLAGS_IS_STATIC_METHOD) {
out = method; out = method;
} else { } else {
@ -928,7 +929,7 @@ int krk_bindMethod(KrkClass * _class, KrkString * name) {
} }
} else if (IS_CLOSURE(method)) { } else if (IS_CLOSURE(method)) {
if (AS_CLOSURE(method)->flags & KRK_FUNCTION_FLAGS_IS_CLASS_METHOD) { if (AS_CLOSURE(method)->flags & KRK_FUNCTION_FLAGS_IS_CLASS_METHOD) {
out = OBJECT_VAL(krk_newBoundMethod(OBJECT_VAL(_class), AS_OBJECT(method))); out = OBJECT_VAL(krk_newBoundMethod(OBJECT_VAL(originalClass), AS_OBJECT(method)));
} else if (AS_CLOSURE(method)->flags & KRK_FUNCTION_FLAGS_IS_STATIC_METHOD) { } else if (AS_CLOSURE(method)->flags & KRK_FUNCTION_FLAGS_IS_STATIC_METHOD) {
out = method; out = method;
} else { } else {

View File

@ -0,0 +1,10 @@
class Foo:
@classmethod
def doThing(cls):
print("Called from a",cls)
class Bar(Foo):
pass
Foo.doThing()
Foo().doThing()
Bar.doThing()
Bar().doThing()

View File

@ -0,0 +1,4 @@
Called from a <class '__main__.Foo'>
Called from a <class '__main__.Foo'>
Called from a <class '__main__.Bar'>
Called from a <class '__main__.Bar'>