Răsfoiți Sursa

fix `super()`

blueloveTH 1 an în urmă
părinte
comite
72e88892e5
5 a modificat fișierele cu 22 adăugiri și 27 ștergeri
  1. 4 4
      include/typings/pkpy.pyi
  2. 0 3
      src/public/internal.c
  3. 16 8
      src/public/modules.c
  4. 0 12
      src/public/py_ops.c
  5. 2 0
      tests/99_extras.py

+ 4 - 4
include/typings/pkpy.pyi

@@ -7,7 +7,7 @@ class TValue[T]:
     @property
     def value(self) -> T: ...
 
-TValue_int = TValue[int]
-TValue_float = TValue[float]
-TValue_vec2i = TValue[vec2i]
-TValue_vec2 = TValue[vec2]
+# TValue_int = TValue[int]
+# TValue_float = TValue[float]
+# TValue_vec2i = TValue[vec2i]
+# TValue_vec2 = TValue[vec2]

+ 0 - 3
src/public/internal.c

@@ -167,9 +167,6 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
         if(py_istype(self, tp_type)) {
             // T.__new__(...)
             type = py_totype(self);
-        } else if(py_istype(self, tp_super)) {
-            // super().__new__(...)
-            type = *(py_Type*)py_touserdata(self);
         } else {
             // invalid usage of `__new__`
             return false;

+ 16 - 8
src/public/modules.c

@@ -756,9 +756,8 @@ py_Type pk_nativefunc__register() {
 }
 
 static bool super__new__(int argc, py_Ref argv) {
-    py_Type* class_arg = py_newobject(py_retval(), tp_super, 1, sizeof(py_Type));
+    py_Type class_arg = 0;
     Frame* frame = pk_current_vm->top_frame;
-    *class_arg = 0;
     py_Ref self_arg = NULL;
     if(argc == 1) {
         // super()
@@ -768,27 +767,36 @@ static bool super__new__(int argc, py_Ref argv) {
             if(callable->type == tp_function) {
                 Function* func = py_touserdata(callable);
                 if(func->clazz != NULL) {
-                    *class_arg = *(py_Type*)PyObject__userdata(func->clazz);
+                    class_arg = *(py_Type*)PyObject__userdata(func->clazz);
                     if(frame->co->nlocals > 0) self_arg = &frame->locals[0];
                 }
             }
         }
         if(class_arg == 0 || self_arg == NULL) return RuntimeError("super(): no arguments");
+        if(self_arg->type == tp_type) {
+            // f(cls, ...)
+            class_arg = pk__type_info(class_arg)->base;
+            if(class_arg == 0) return RuntimeError("super(): base class is invalid");
+            py_assign(py_retval(), py_tpobject(class_arg));
+            return true;
+        }
     } else if(argc == 3) {
-        // super(type, obj)
+        // super(type[T], obj)
         PY_CHECK_ARG_TYPE(1, tp_type);
-        *class_arg = py_totype(py_arg(1));
+        class_arg = py_totype(py_arg(1));
         self_arg = py_arg(2);
-        if(!py_isinstance(self_arg, *class_arg)) {
+        if(!py_isinstance(self_arg, class_arg)) {
             return TypeError("super(type, obj): obj must be an instance of type");
         }
     } else {
         return TypeError("super() takes 0 or 2 arguments");
     }
 
-    *class_arg = pk__type_info(*class_arg)->base;
-    if(*class_arg == 0) return RuntimeError("super(): base class is invalid");
+    class_arg = pk__type_info(class_arg)->base;
+    if(class_arg == 0) return RuntimeError("super(): base class is invalid");
 
+    py_Type* p_class_arg = py_newobject(py_retval(), tp_super, 1, sizeof(py_Type));
+    *p_class_arg = class_arg;
     py_setslot(py_retval(), 0, self_arg);
     return true;
 }

+ 0 - 12
src/public/py_ops.c

@@ -87,12 +87,6 @@ int py_next(py_Ref val) {
 bool py_getattr(py_Ref self, py_Name name) {
     // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
     py_Type type = self->type;
-    // handle super() proxy (disabled)
-    // if(py_istype(self, tp_super)) {
-    //     self = py_getslot(self, 0);
-    //     type = *(py_Type*)py_touserdata(self);
-    // }
-
     py_Ref cls_var = py_tpfindname(type, name);
     if(cls_var) {
         // handle descriptor
@@ -183,12 +177,6 @@ bool py_getattr(py_Ref self, py_Name name) {
 
 bool py_setattr(py_Ref self, py_Name name, py_Ref val) {
     py_Type type = self->type;
-    // handle super() proxy (disabled)
-    // if(py_istype(self, tp_super)) {
-    //     self = py_getslot(self, 0);
-    //     type = *(py_Type*)py_touserdata(self);
-    // }
-
     py_Ref cls_var = py_tpfindname(type, name);
     if(cls_var) {
         // handle descriptor

+ 2 - 0
tests/99_extras.py

@@ -78,6 +78,7 @@ class Z:
 
 class B(Z):
     def __new__(cls, x):
+        assert super() is Z
         return super().__new__(cls, x)
 
 assert Z(1) == (Z, 1)
@@ -87,6 +88,7 @@ from pkpy import TValue
 
 class fixed(TValue[int]):
     def __new__(cls, value: str):
+        assert super() is TValue[int]
         return super().__new__(cls, int(value))
     
 assert fixed('123').value == 123