]> granicus.if.org Git - php/commitdiff
Fix bug #79925
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 3 Aug 2020 08:34:39 +0000 (10:34 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 3 Aug 2020 08:35:26 +0000 (10:35 +0200)
If the expected return type of a magic method is "object", we also
need to allow class types and "static" to comply with covariance.

Zend/tests/magic_methods_021.phpt [new file with mode: 0644]
Zend/zend_API.c

diff --git a/Zend/tests/magic_methods_021.phpt b/Zend/tests/magic_methods_021.phpt
new file mode 100644 (file)
index 0000000..fd3e7fa
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+__set_state return type should support covariance
+--FILE--
+<?php
+
+class Foo {
+    public static function __set_state(array $data): self {}
+}
+
+class Foo2 {
+    public static function __set_state(array $data): static {}
+}
+
+class Foo3 {
+    public static function __set_state(array $data): Foo3|self {}
+}
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
index c2f887a5bcc6c1e8eea494f1da29c4ebec0cb6b4..9906d7b423bc84c585e2a46d67ddc369ae0e435c 100644 (file)
@@ -2063,10 +2063,19 @@ static void zend_check_magic_method_arg_type(uint32_t arg_num, const zend_class_
 
 static void zend_check_magic_method_return_type(const zend_class_entry *ce, const zend_function *fptr, int error_type, int return_type)
 {
-       if (
-               (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)
-               && (ZEND_TYPE_FULL_MASK(fptr->common.arg_info[-1].type) & ~return_type)
-       ) {
+       if (!(fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
+               /* For backwards compatibility reasons, do not enforce the return type if it is not set. */
+               return;
+       }
+
+       bool has_class_type = ZEND_TYPE_HAS_CLASS(fptr->common.arg_info[-1].type);
+       uint32_t extra_types = ZEND_TYPE_PURE_MASK(fptr->common.arg_info[-1].type) & ~return_type;
+       if (extra_types & MAY_BE_STATIC) {
+               extra_types &= ~MAY_BE_STATIC;
+               has_class_type = 1;
+       }
+
+       if (extra_types || (has_class_type && return_type != MAY_BE_OBJECT)) {
                zend_error(error_type, "%s::%s(): Return type must be %s when declared",
                        ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name),
                        ZSTR_VAL(zend_type_to_string((zend_type) ZEND_TYPE_INIT_MASK(return_type))));