[prev in list] [next in list] [prev in thread] [next in thread] 

List:       php-cvs
Subject:    [PHP-CVS] [php-src] PHP-8.2: Fix GH-9556 "iterable" alias "array|Traversable" breaks PHP 8.1 code
From:       George Peter Banyard <noreply () php ! net>
Date:       2022-09-30 11:45:47
Message-ID: o9jYOLVTkis7KilUDnj1vWGOtXbN7yNs4JpikTgoI () main ! php ! net
[Download RAW message or body]

Author: George Peter Banyard (Girgias)
Date: 2022-09-30T12:49:15+01:00

Commit: https://github.com/php/php-src/commit/c801076d8bd7e5d31b0dfbdc8e4e3d26fd242738
 Raw diff: https://github.com/php/php-src/commit/c801076d8bd7e5d31b0dfbdc8e4e3d26fd242738.diff


Fix GH-9556 "iterable" alias "array|Traversable" breaks PHP 8.1 code

Closes GH-9558

Changed paths:
  A  Zend/tests/type_declarations/dnf_types/redundant_types/object_and_dnf_type.phpt
  A  Zend/tests/type_declarations/dnf_types/redundant_types/object_and_dnf_type2.phpt
  A  Zend/tests/type_declarations/iterable/iterable_alias_redundancy_array_1.phpt
  A  Zend/tests/type_declarations/iterable/iterable_alias_redundancy_array_2.phpt
  A  Zend/tests/type_declarations/iterable/iterable_alias_redundancy_iterable.phpt
  A  Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_1.phpt
  A  Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_2.phpt
  A  Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_3.phpt
  A  Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_4.phpt
  A  Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_5.phpt
  A  Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_6.phpt
  A  Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_variance.phpt
  A  Zend/tests/type_declarations/union_types/redundant_types/object_and_class_type2.phpt
  A  Zend/tests/type_declarations/union_types/redundant_types/object_and_static2.phpt
  M  Zend/zend_compile.c


Diff:

diff --git a/Zend/tests/type_declarations/dnf_types/redundant_types/object_and_dnf_type.phpt \
b/Zend/tests/type_declarations/dnf_types/redundant_types/object_and_dnf_type.phpt new \
file mode 100644 index 000000000000..3a99d3a5d520
--- /dev/null
+++ b/Zend/tests/type_declarations/dnf_types/redundant_types/object_and_dnf_type.phpt
@@ -0,0 +1,14 @@
+--TEST--
+A DNF type which contains object is redundant
+--FILE--
+<?php
+
+interface A {}
+interface B {}
+
+function test(): (A&B)|object {}
+
+?>
+===DONE===
+--EXPECTF--
+Fatal error: Type (A&B)|object contains both object and a class type, which is \
                redundant in %s on line %d
diff --git a/Zend/tests/type_declarations/dnf_types/redundant_types/object_and_dnf_type2.phpt \
b/Zend/tests/type_declarations/dnf_types/redundant_types/object_and_dnf_type2.phpt \
new file mode 100644 index 000000000000..c37f08d6dc41
--- /dev/null
+++ b/Zend/tests/type_declarations/dnf_types/redundant_types/object_and_dnf_type2.phpt
 @@ -0,0 +1,14 @@
+--TEST--
+A DNF type which contains object is redundant 2
+--FILE--
+<?php
+
+interface A {}
+interface B {}
+
+function test(): object|(A&B) {}
+
+?>
+===DONE===
+--EXPECTF--
+Fatal error: Type (A&B)|object contains both object and a class type, which is \
                redundant in %s on line %d
diff --git a/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_array_1.phpt \
b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_array_1.phpt new \
file mode 100644 index 000000000000..b11671bc0924
--- /dev/null
+++ b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_array_1.phpt
@@ -0,0 +1,12 @@
+--TEST--
+iterable type with array should be redundant
+--FILE--
+<?php
+
+function bar(): array|iterable|null {
+    return null;
+}
+
+?>
+--EXPECTF--
+Fatal error: Duplicate type array is redundant in %s on line %d
diff --git a/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_array_2.phpt \
b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_array_2.phpt new \
file mode 100644 index 000000000000..6973901cb5a2
--- /dev/null
+++ b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_array_2.phpt
@@ -0,0 +1,12 @@
+--TEST--
+iterable type with array should be redundant
+--FILE--
+<?php
+
+function bar(): iterable|array|null {
+    return null;
+}
+
+?>
+--EXPECTF--
+Fatal error: Duplicate type array is redundant in %s on line %d
diff --git a/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_iterable.phpt \
b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_iterable.phpt new \
file mode 100644 index 000000000000..e8fa3c040261
--- /dev/null
+++ b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_iterable.phpt
@@ -0,0 +1,12 @@
+--TEST--
+iterable type with second iterable should be redundant
+--FILE--
+<?php
+
+function bar(): iterable|iterable|null {
+    return null;
+}
+
+?>
+--EXPECTF--
+Fatal error: Duplicate type array is redundant in %s on line %d
diff --git a/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_1.phpt \
b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_1.phpt new \
file mode 100644 index 000000000000..b7a70191145f
--- /dev/null
+++ b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_1.phpt
@@ -0,0 +1,13 @@
+--TEST--
+iterable type with object should NOT be redundant 1
+--FILE--
+<?php
+
+function bar(): iterable|object|null {
+    return null;
+}
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_2.phpt \
b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_2.phpt new \
file mode 100644 index 000000000000..07a666823295
--- /dev/null
+++ b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_2.phpt
@@ -0,0 +1,13 @@
+--TEST--
+iterable type with object should NOT be redundant 2
+--FILE--
+<?php
+
+function bar(): object|iterable|null {
+    return null;
+}
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_3.phpt \
b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_3.phpt new \
file mode 100644 index 000000000000..eedf16fd7649
--- /dev/null
+++ b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_3.phpt
@@ -0,0 +1,12 @@
+--TEST--
+iterable type with object and class T should be redundant
+--FILE--
+<?php
+
+function bar(): object|iterable|T|null {
+    return null;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type Traversable|T|object|array|null contains both object and a class \
                type, which is redundant in %s on line %d
diff --git a/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_4.phpt \
b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_4.phpt new \
file mode 100644 index 000000000000..acad787130a6
--- /dev/null
+++ b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_4.phpt
@@ -0,0 +1,12 @@
+--TEST--
+iterable type with object and class T should be redundant
+--FILE--
+<?php
+
+function bar(): iterable|object|T|null {
+    return null;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type Traversable|T|object|array|null contains both object and a class \
                type, which is redundant in %s on line %d
diff --git a/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_5.phpt \
b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_5.phpt new \
file mode 100644 index 000000000000..84ba505aa7da
--- /dev/null
+++ b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_5.phpt
@@ -0,0 +1,12 @@
+--TEST--
+iterable type with object and class T should be redundant
+--FILE--
+<?php
+
+function bar(): T|object|iterable|null {
+    return null;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type T|Traversable|object|array|null contains both object and a class \
                type, which is redundant in %s on line %d
diff --git a/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_6.phpt \
b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_6.phpt new \
file mode 100644 index 000000000000..541317d1d696
--- /dev/null
+++ b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_6.phpt
@@ -0,0 +1,12 @@
+--TEST--
+iterable type with object and class T should be redundant
+--FILE--
+<?php
+
+function bar(): T|iterable|object|null {
+    return null;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type T|Traversable|object|array|null contains both object and a class \
                type, which is redundant in %s on line %d
diff --git a/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_variance.phpt \
b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_variance.phpt
 new file mode 100644
index 000000000000..158b6c2214f4
--- /dev/null
+++ b/Zend/tests/type_declarations/iterable/iterable_alias_redundancy_object_variance.phpt
 @@ -0,0 +1,18 @@
+--TEST--
+iterable type with object should be allowed in variance checks
+--FILE--
+<?php
+
+class A {
+    public object|iterable $x;
+    public object|array $y;
+}
+class B extends A {
+    public object|array $x;
+    public object|iterable $y;
+}
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/Zend/tests/type_declarations/union_types/redundant_types/object_and_class_type2.phpt \
b/Zend/tests/type_declarations/union_types/redundant_types/object_and_class_type2.phpt
 new file mode 100644
index 000000000000..bc9852da83d1
--- /dev/null
+++ b/Zend/tests/type_declarations/union_types/redundant_types/object_and_class_type2.phpt
 @@ -0,0 +1,11 @@
+--TEST--
+Using both object and a class type 2
+--FILE--
+<?php
+
+function test(): Test|object {
+}
+
+?>
+--EXPECTF--
+Fatal error: Type Test|object contains both object and a class type, which is \
                redundant in %s on line %d
diff --git a/Zend/tests/type_declarations/union_types/redundant_types/object_and_static2.phpt \
b/Zend/tests/type_declarations/union_types/redundant_types/object_and_static2.phpt \
new file mode 100644 index 000000000000..3fbb9a29fe5a
--- /dev/null
+++ b/Zend/tests/type_declarations/union_types/redundant_types/object_and_static2.phpt
 @@ -0,0 +1,12 @@
+--TEST--
+object and static are redundant 2
+--FILE--
+<?php
+
+class Test {
+    public function foo(): object|static {}
+}
+
+?>
+--EXPECTF--
+Fatal error: Type static|object contains both object and a class type, which is \
                redundant in %s on line %d
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index f1dce379ae86..154c5a810ba6 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -6363,6 +6363,7 @@ static zend_type zend_compile_typename(
 		zend_ast_list *list = zend_ast_get_list(ast);
 		zend_type_list *type_list;
 		bool is_composite = false;
+		bool has_only_iterable_class = true;
 		ALLOCA_FLAG(use_heap)
 
 		type_list = do_alloca(ZEND_TYPE_LIST_SIZE(list->children), use_heap);
@@ -6371,8 +6372,10 @@ static zend_type zend_compile_typename(
 		for (uint32_t i = 0; i < list->children; i++) {
 			zend_ast *type_ast = list->child[i];
 			zend_type single_type;
+			uint32_t type_mask = ZEND_TYPE_FULL_MASK(type);
 
 			if (type_ast->kind == ZEND_AST_TYPE_INTERSECTION) {
+				has_only_iterable_class = false;
 				is_composite = true;
 				/* The first class type can be stored directly as the type ptr payload. */
 				if (ZEND_TYPE_IS_COMPLEX(type) && !ZEND_TYPE_HAS_LIST(type)) {
@@ -6380,8 +6383,9 @@ static zend_type zend_compile_typename(
 					type_list->num_types = 1;
 					type_list->types[0] = type;
 					ZEND_TYPE_FULL_MASK(type_list->types[0]) &= ~_ZEND_TYPE_MAY_BE_MASK;
-					ZEND_TYPE_SET_LIST(type, type_list);
 				}
+				/* Mark type as list type */
+				ZEND_TYPE_SET_LIST(type, type_list);
 
 				single_type = zend_compile_typename(type_ast, false);
 				ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(single_type));
@@ -6406,6 +6410,9 @@ static zend_type zend_compile_typename(
 			if (single_type_mask == MAY_BE_ANY) {
 				zend_error_noreturn(E_COMPILE_ERROR, "Type mixed can only be used as a \
standalone type");  }
+			if (ZEND_TYPE_IS_COMPLEX(single_type) && \
!ZEND_TYPE_IS_ITERABLE_FALLBACK(single_type)) { +				has_only_iterable_class = false;
+			}
 
 			uint32_t type_mask_overlap = ZEND_TYPE_PURE_MASK(type) & single_type_mask;
 			if (type_mask_overlap) {
@@ -6414,8 +6421,9 @@ static zend_type zend_compile_typename(
 				zend_error_noreturn(E_COMPILE_ERROR,
 					"Duplicate type %s is redundant", ZSTR_VAL(overlap_type_str));
 			}
-			if ( ((ZEND_TYPE_PURE_MASK(type) & MAY_BE_TRUE) && (single_type_mask == \
                MAY_BE_FALSE))
-					|| ((ZEND_TYPE_PURE_MASK(type) & MAY_BE_FALSE) && (single_type_mask == \
MAY_BE_TRUE)) ) { +
+			if ( ((type_mask & MAY_BE_TRUE) && (single_type_mask == MAY_BE_FALSE))
+					|| ((type_mask & MAY_BE_FALSE) && (single_type_mask == MAY_BE_TRUE)) ) {
 				zend_error_noreturn(E_COMPILE_ERROR,
 					"Type contains both true and false, bool should be used instead");
 			}
@@ -6457,7 +6465,8 @@ static zend_type zend_compile_typename(
 		free_alloca(type_list, use_heap);
 
 		uint32_t type_mask = ZEND_TYPE_FULL_MASK(type);
-		if ((type_mask & MAY_BE_OBJECT) && (ZEND_TYPE_IS_COMPLEX(type) || (type_mask & \
MAY_BE_STATIC))) { +		if ((type_mask & MAY_BE_OBJECT) &&
+				((!has_only_iterable_class && ZEND_TYPE_IS_COMPLEX(type)) || (type_mask & \
MAY_BE_STATIC))) {  zend_string *type_str = zend_type_to_string(type);
 			zend_error_noreturn(E_COMPILE_ERROR,
 				"Type %s contains both object and a class type, which is redundant",

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic