diff --git a/src/core/core.c b/src/core/core.c index 2dfaaab8..387f0ecf 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -1590,11 +1590,11 @@ Var getMethod(PKVM* vm, Var self, String* name, bool* is_method) { return varGetAttrib(vm, self, name); } -Closure* getSuperMethod(PKVM* vm, Var self, String* name) { - Class* super = getClass(vm, self)->super_class; +Closure* getSuperMethod(PKVM* vm, Class* class, String* name) { + Class* super = NULL == class ? NULL : class->super_class; if (super == NULL) { - VM_SET_ERROR(vm, stringFormat(vm, "'$' object has no parent class.", \ - varTypeName(self))); + VM_SET_ERROR(vm, stringFormat(vm, "'$' has no parent class.", \ + class->name)); return NULL; }; diff --git a/src/core/core.h b/src/core/core.h index ec89b087..f153e2c8 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -89,7 +89,7 @@ Var getMethod(PKVM* vm, Var self, String* name, bool* is_method); // Returns the method (closure) from the instance's super class. If the method // doesn't exists, it'll set an error on the VM. -Closure* getSuperMethod(PKVM* vm, Var self, String* name); +Closure* getSuperMethod(PKVM* vm, Class* class, String* name); // Unlike getMethod this will not set error and will not try to get attribute // with the same name. It'll return true if the method exists on [self], false diff --git a/src/core/public.c b/src/core/public.c index 3601492d..7e6d1d61 100644 --- a/src/core/public.c +++ b/src/core/public.c @@ -306,6 +306,7 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls, // won't be garbage collected (class handle has reference to the module). Closure* method = newClosure(vm, fn); + method->class = class_; vmPopTempRef(vm); // fn. vmPushTempRef(vm, &method->_super); // method. { diff --git a/src/core/value.h b/src/core/value.h index 177ad890..832431b8 100644 --- a/src/core/value.h +++ b/src/core/value.h @@ -402,6 +402,7 @@ struct Function { struct Closure { Object _super; + Class* class; Function* fn; Upvalue* upvalues[DYNAMIC_TAIL_ARRAY]; }; diff --git a/src/core/vm.c b/src/core/vm.c index 8b8eeaaf..c68cd0ec 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -1130,6 +1130,8 @@ PkResult vmRunFiber(PKVM* vm, Fiber* fiber_) { cls->ctor = method; } + method->class = cls; + pkClosureBufferWrite(&cls->methods, vm, method); DROP(); @@ -1198,7 +1200,9 @@ PkResult vmRunFiber(PKVM* vm, Fiber* fiber_) { fiber->self = *fiber->ret; //< Self for the next call. index = READ_SHORT(); name = moduleGetStringAt(module, (int)index); - Closure* super_method = getSuperMethod(vm, fiber->self, name); + Class* class = frame->closure->class; + if ( NULL == class ) class = getClass( vm, fiber->self ); + Closure* super_method = getSuperMethod(vm, class, name); CHECK_ERROR(); // Will return if super_method is NULL. callable = VAR_OBJ(super_method); goto L_do_call; @@ -1253,6 +1257,7 @@ PkResult vmRunFiber(PKVM* vm, Fiber* fiber_) { *fiber->ret = fiber->self; closure = (const Closure*)(cls)->ctor; + const char* class_name = cls->name->data; while (closure == NULL) { cls = cls->super_class; if (cls == NULL) break; @@ -1263,7 +1268,7 @@ PkResult vmRunFiber(PKVM* vm, Fiber* fiber_) { if (closure == NULL) { if (argc != 0) { String* msg = stringFormat(vm, "Expected exactly 0 argument(s) " - "for constructor $.", cls->name->data); + "for constructor $.", class_name ); RUNTIME_ERROR(msg); } diff --git a/tests/lang/class.pk b/tests/lang/class.pk index 043703cb..e5d12136 100644 --- a/tests/lang/class.pk +++ b/tests/lang/class.pk @@ -246,7 +246,20 @@ class B is A end end +class C is B + def _init() + super() + print("C init") + end + def foo() + print("C foo") + return super.foo() + end +end + b = B() assert(b.foo() == "A.bar") +c = C() +assert(c.foo() == "A.bar") print('ALL TESTS PASSED')