فهرست منبع

fix a bug of `__init__`

blueloveTH 1 هفته پیش
والد
کامیت
71f06c4ff1
2فایلهای تغییر یافته به همراه22 افزوده شده و 9 حذف شده
  1. 11 8
      src/interpreter/vm.c
  2. 11 1
      tests/410_class_ex.py

+ 11 - 8
src/interpreter/vm.c

@@ -579,8 +579,9 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
     }
     }
 
 
     if(p0->type == tp_type) {
     if(p0->type == tp_type) {
+        py_Type p0_type = py_totype(p0);
         // [cls, NULL, args..., kwargs...]
         // [cls, NULL, args..., kwargs...]
-        py_Ref new_f = py_tpfindmagic(py_totype(p0), __new__);
+        py_Ref new_f = py_tpfindmagic(p0_type, __new__);
         assert(new_f && py_isnil(p0 + 1));
         assert(new_f && py_isnil(p0 + 1));
         bool is_default_new = new_f->type == tp_nativefunc && new_f->_cfunc == pk__object_new;
         bool is_default_new = new_f->type == tp_nativefunc && new_f->_cfunc == pk__object_new;
 
 
@@ -598,14 +599,16 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
         // NOTE: previously we use `get_unbound_method` but here we just use `tpfindmagic`
         // NOTE: previously we use `get_unbound_method` but here we just use `tpfindmagic`
         // >> [cls, NULL, args..., kwargs...]
         // >> [cls, NULL, args..., kwargs...]
         // >> py_retval() is the new instance
         // >> py_retval() is the new instance
-        py_Ref init_f = py_tpfindmagic(py_totype(p0), __init__);
+        py_Ref init_f = py_tpfindmagic(p0_type, __init__);
         if(init_f) {
         if(init_f) {
-            // do an inplace patch
-            *p0 = *init_f;              // __init__
-            p0[1] = self->last_retval;  // self
-            // [__init__, self, args..., kwargs...]
-            if(VM__vectorcall(self, argc, kwargc, false) == RES_ERROR) return RES_ERROR;
-            *py_retval() = p0[1];  // restore the new instance
+            if(py_isinstance(py_retval(), p0_type)) {
+                // do an inplace patch
+                *p0 = *init_f;              // __init__
+                p0[1] = self->last_retval;  // self
+                // [__init__, self, args..., kwargs...]
+                if(VM__vectorcall(self, argc, kwargc, false) == RES_ERROR) return RES_ERROR;
+                *py_retval() = p0[1];  // restore the new instance
+            }
         } else {
         } else {
             if(is_default_new) {
             if(is_default_new) {
                 if(argc != 0 || kwargc != 0) {
                 if(argc != 0 || kwargc != 0) {

+ 11 - 1
tests/410_class_ex.py

@@ -167,4 +167,14 @@ class DerivedClass(BaseClass):
         return super().f()
         return super().f()
 
 
     
     
-assert DerivedClass.f() == 'BaseClass'
+assert DerivedClass.f() == 'BaseClass'
+
+# bad __init__
+class A:
+    def __new__(cls, *args, **kwargs):
+        return 1
+
+    def __init__(self):
+        assert False
+
+A()