Skip to content

Commit 55860a2

Browse files
committed
Address review and drop BC shim for unions
1 parent ae83f41 commit 55860a2

17 files changed

+122
-99
lines changed

Zend/tests/return_types/generators001.phpt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,18 @@ function test6() : object|callable {
2626
yield 6;
2727
}
2828

29+
function test7() : iterable {
30+
yield 7;
31+
}
32+
2933
var_dump(
3034
test1(),
3135
test2(),
3236
test3(),
3337
test4(),
3438
test5(),
3539
test6(),
40+
test7(),
3641
);
3742
?>
3843
--EXPECTF--
@@ -48,3 +53,5 @@ object(Generator)#%d (%d) {
4853
}
4954
object(Generator)#%d (%d) {
5055
}
56+
object(Generator)#%d (%d) {
57+
}

Zend/tests/type_declarations/intersection_types/variance/invalid5.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ class Test2 extends Test {
1515

1616
?>
1717
--EXPECTF--
18-
Fatal error: Declaration of Test2::method(): X&Y must be compatible with Test::method(): iterable in %s on line %d
18+
Fatal error: Declaration of Test2::method(): X&Y must be compatible with Test::method(): Traversable|array in %s on line %d

Zend/tests/type_declarations/iterable_001.phpt renamed to Zend/tests/type_declarations/iterable/iterable_001.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,4 @@ object(ArrayIterator)#1 (1) {
4545
int(3)
4646
}
4747
}
48-
test(): Argument #1 ($iterable) must be of type iterable, int given, called in %s on line %d
48+
test(): Argument #1 ($iterable) must be of type Traversable|array, int given, called in %s on line %d

Zend/tests/type_declarations/iterable_002.phpt renamed to Zend/tests/type_declarations/iterable/iterable_002.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ function baz(iterable $iterable = 1) {
1717

1818
?>
1919
--EXPECTF--
20-
Fatal error: Cannot use int as default value for parameter $iterable of type iterable in %s on line %d
20+
Fatal error: Cannot use int as default value for parameter $iterable of type Traversable|array in %s on line %d

Zend/tests/type_declarations/iterable_003.phpt renamed to Zend/tests/type_declarations/iterable/iterable_003.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ array(0) {
2929
}
3030
object(Generator)#2 (0) {
3131
}
32-
baz(): Return value must be of type iterable, int returned
32+
baz(): Return value must be of type Traversable|array, int returned

Zend/tests/type_declarations/iterable_004.phpt renamed to Zend/tests/type_declarations/iterable/iterable_004.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ class Bar extends Foo {
2121

2222
?>
2323
--EXPECTF--
24-
Fatal error: Declaration of Bar::testScalar(iterable $iterable) must be compatible with Foo::testScalar(int $int) in %s on line %d
24+
Fatal error: Declaration of Bar::testScalar(Traversable|array $iterable) must be compatible with Foo::testScalar(int $int) in %s on line %d

Zend/tests/type_declarations/iterable_005.phpt renamed to Zend/tests/type_declarations/iterable/iterable_005.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ class TestScalar extends Test {
2929

3030
?>
3131
--EXPECTF--
32-
Fatal error: Declaration of TestScalar::method(): int must be compatible with Test::method(): iterable in %s on line %d
32+
Fatal error: Declaration of TestScalar::method(): int must be compatible with Test::method(): Traversable|array in %s on line %d
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
Test "or null"/"or be null" in type-checking errors for userland functions with iterable
3+
--FILE--
4+
<?php
5+
6+
// This should test every branch in zend_execute.c's `zend_verify_arg_type`, `zend_verify_return_type` and `zend_verify_missing_return_type` functions which produces an "or null"/"or be null" part in its error message
7+
8+
function iterableF(?iterable $param) {}
9+
try {
10+
iterableF(1);
11+
} catch (\TypeError $e) {
12+
echo $e, PHP_EOL;
13+
}
14+
15+
function returnIterable(): ?iterable {
16+
return 1;
17+
}
18+
19+
try {
20+
returnIterable();
21+
} catch (\TypeError $e) {
22+
echo $e, PHP_EOL;
23+
}
24+
25+
function returnMissingIterable(): ?iterable {
26+
}
27+
28+
try {
29+
returnMissingIterable();
30+
} catch (\TypeError $e) {
31+
echo $e, PHP_EOL;
32+
}
33+
?>
34+
--EXPECTF--
35+
TypeError: iterableF(): Argument #1 ($param) must be of type Traversable|array|null, int given, called in %s on line %d and defined in %s:%d
36+
Stack trace:
37+
#0 %s(%d): iterableF(1)
38+
#1 {main}
39+
TypeError: returnIterable(): Return value must be of type Traversable|array|null, int returned in %s:%d
40+
Stack trace:
41+
#0 %s(%d): returnIterable()
42+
#1 {main}
43+
TypeError: returnMissingIterable(): Return value must be of type Traversable|array|null, none returned in %s:%d
44+
Stack trace:
45+
#0 %s(%d): returnMissingIterable()
46+
#1 {main}

Zend/tests/typehints/or_null.phpt

Lines changed: 21 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,6 @@ try {
5757
echo $e, PHP_EOL;
5858
}
5959

60-
function iterableF(?iterable $param) {}
61-
62-
try {
63-
iterableF(1);
64-
} catch (\TypeError $e) {
65-
echo $e, PHP_EOL;
66-
}
67-
6860
function intF(?int $param) {}
6961

7062
try {
@@ -143,16 +135,6 @@ try {
143135
echo $e, PHP_EOL;
144136
}
145137

146-
function returnIterable(): ?iterable {
147-
return 1;
148-
}
149-
150-
try {
151-
returnIterable();
152-
} catch (\TypeError $e) {
153-
echo $e, PHP_EOL;
154-
}
155-
156138
function returnInt(): ?int {
157139
return new \StdClass;
158140
}
@@ -199,15 +181,6 @@ try {
199181
echo $e, PHP_EOL;
200182
}
201183

202-
function returnMissingIterable(): ?iterable {
203-
}
204-
205-
try {
206-
returnMissingIterable();
207-
} catch (\TypeError $e) {
208-
echo $e, PHP_EOL;
209-
}
210-
211184
function returnMissingInt(): ?int {
212185
}
213186

@@ -221,97 +194,85 @@ try {
221194
--EXPECTF--
222195
TypeError: unloadedClass(): Argument #1 ($param) must be of type ?I\Dont\Exist, stdClass given, called in %s:%d
223196
Stack trace:
224-
#0 %s(8): unloadedClass(Object(stdClass))
197+
#0 %s(%d): unloadedClass(Object(stdClass))
225198
#1 {main}
226199
TypeError: loadedClass(): Argument #1 ($param) must be of type ?RealClass, stdClass given, called in %s:%d
227200
Stack trace:
228-
#0 %s(20): loadedClass(Object(stdClass))
201+
#0 %s(%d): loadedClass(Object(stdClass))
229202
#1 {main}
230203
TypeError: loadedInterface(): Argument #1 ($param) must be of type ?RealInterface, stdClass given, called in %s:%d
231204
Stack trace:
232-
#0 %s(26): loadedInterface(Object(stdClass))
205+
#0 %s(%d): loadedInterface(Object(stdClass))
233206
#1 {main}
234207
TypeError: unloadedClass(): Argument #1 ($param) must be of type ?I\Dont\Exist, int given, called in %s:%d
235208
Stack trace:
236-
#0 %s(32): unloadedClass(1)
209+
#0 %s(%d): unloadedClass(1)
237210
#1 {main}
238211
TypeError: loadedClass(): Argument #1 ($param) must be of type ?RealClass, int given, called in %s:%d
239212
Stack trace:
240-
#0 %s(38): loadedClass(1)
213+
#0 %s(%d): loadedClass(1)
241214
#1 {main}
242215
TypeError: loadedInterface(): Argument #1 ($param) must be of type ?RealInterface, int given, called in %s:%d
243216
Stack trace:
244-
#0 %s(44): loadedInterface(1)
217+
#0 %s(%d): loadedInterface(1)
245218
#1 {main}
246219
TypeError: callableF(): Argument #1 ($param) must be of type ?callable, int given, called in %s:%d
247220
Stack trace:
248-
#0 %s(52): callableF(1)
249-
#1 {main}
250-
TypeError: iterableF(): Argument #1 ($param) must be of type ?iterable, int given, called in %s:%d
251-
Stack trace:
252-
#0 %s(60): iterableF(1)
221+
#0 %s(%d): callableF(1)
253222
#1 {main}
254223
TypeError: intF(): Argument #1 ($param) must be of type ?int, stdClass given, called in %s:%d
255224
Stack trace:
256-
#0 %s(68): intF(Object(stdClass))
225+
#0 %s(%d): intF(Object(stdClass))
257226
#1 {main}
258227
TypeError: returnUnloadedClass(): Return value must be of type ?I\Dont\Exist, stdClass returned in %s:%d
259228
Stack trace:
260-
#0 %s(78): returnUnloadedClass()
229+
#0 %s(%d): returnUnloadedClass()
261230
#1 {main}
262231
TypeError: returnLoadedClass(): Return value must be of type ?RealClass, stdClass returned in %s:%d
263232
Stack trace:
264-
#0 %s(88): returnLoadedClass()
233+
#0 %s(%d): returnLoadedClass()
265234
#1 {main}
266235
TypeError: returnLoadedInterface(): Return value must be of type ?RealInterface, stdClass returned in %s:%d
267236
Stack trace:
268-
#0 %s(98): returnLoadedInterface()
237+
#0 %s(%d): returnLoadedInterface()
269238
#1 {main}
270239
TypeError: returnUnloadedClassScalar(): Return value must be of type ?I\Dont\Exist, int returned in %s:%d
271240
Stack trace:
272-
#0 %s(108): returnUnloadedClassScalar()
241+
#0 %s(%d): returnUnloadedClassScalar()
273242
#1 {main}
274243
TypeError: returnLoadedClassScalar(): Return value must be of type ?RealClass, int returned in %s:%d
275244
Stack trace:
276-
#0 %s(118): returnLoadedClassScalar()
245+
#0 %s(%d): returnLoadedClassScalar()
277246
#1 {main}
278247
TypeError: returnLoadedInterfaceScalar(): Return value must be of type ?RealInterface, int returned in %s:%d
279248
Stack trace:
280-
#0 %s(128): returnLoadedInterfaceScalar()
249+
#0 %s(%d): returnLoadedInterfaceScalar()
281250
#1 {main}
282251
TypeError: returnCallable(): Return value must be of type ?callable, int returned in %s:%d
283252
Stack trace:
284-
#0 %s(138): returnCallable()
285-
#1 {main}
286-
TypeError: returnIterable(): Return value must be of type ?iterable, int returned in %s:%d
287-
Stack trace:
288-
#0 %s(148): returnIterable()
253+
#0 %s(%d): returnCallable()
289254
#1 {main}
290255
TypeError: returnInt(): Return value must be of type ?int, stdClass returned in %s:%d
291256
Stack trace:
292-
#0 %s(158): returnInt()
257+
#0 %s(%d): returnInt()
293258
#1 {main}
294259
TypeError: returnMissingUnloadedClass(): Return value must be of type ?I\Dont\Exist, none returned in %s:%d
295260
Stack trace:
296-
#0 %s(167): returnMissingUnloadedClass()
261+
#0 %s(%d): returnMissingUnloadedClass()
297262
#1 {main}
298263
TypeError: returnMissingLoadedClass(): Return value must be of type ?RealClass, none returned in %s:%d
299264
Stack trace:
300-
#0 %s(176): returnMissingLoadedClass()
265+
#0 %s(%d): returnMissingLoadedClass()
301266
#1 {main}
302267
TypeError: returnMissingLoadedInterface(): Return value must be of type ?RealInterface, none returned in %s:%d
303268
Stack trace:
304-
#0 %s(185): returnMissingLoadedInterface()
269+
#0 %s(%d): returnMissingLoadedInterface()
305270
#1 {main}
306271
TypeError: returnMissingCallable(): Return value must be of type ?callable, none returned in %s:%d
307272
Stack trace:
308-
#0 %s(194): returnMissingCallable()
309-
#1 {main}
310-
TypeError: returnMissingIterable(): Return value must be of type ?iterable, none returned in %s:%d
311-
Stack trace:
312-
#0 %s(203): returnMissingIterable()
273+
#0 %s(%d): returnMissingCallable()
313274
#1 {main}
314275
TypeError: returnMissingInt(): Return value must be of type ?int, none returned in %s:%d
315276
Stack trace:
316-
#0 %s(212): returnMissingInt()
277+
#0 %s(%d): returnMissingInt()
317278
#1 {main}

Zend/zend_compile.c

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,29 +1192,11 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
11921192
uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
11931193
bool has_name = ZEND_TYPE_HAS_NAME(type);
11941194

1195-
/* BC for iterable type as a single type */
1196-
if (UNEXPECTED(ZEND_TYPE_IS_ITERABLE_FALLBACK(type))) {
1197-
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_ITERABLE), /* is_intersection */ false);
1198-
/* Remove array bit */
1199-
type_mask &= ~MAY_BE_ARRAY;
1200-
/* If it has a type name it must be Traversable, ignore it */
1201-
if (has_name) {
1202-
has_name = false;
1203-
}
1204-
}
1205-
12061195
if (ZEND_TYPE_HAS_LIST(type)) {
12071196
zend_type *list_type;
12081197
bool is_intersection = ZEND_TYPE_IS_INTERSECTION(type);
12091198
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
12101199
zend_string *name = ZEND_TYPE_NAME(*list_type);
1211-
/* BC for iterable type in a union type */
1212-
if (UNEXPECTED(ZEND_TYPE_IS_ITERABLE_FALLBACK(*list_type) && zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_TRAVERSABLE)))) {
1213-
/* Remove array bit */
1214-
type_mask &= ~MAY_BE_ARRAY;
1215-
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_ITERABLE), /* is_intersection */ false);
1216-
continue;
1217-
}
12181200
zend_string *resolved = resolve_class_name(name, scope);
12191201
str = add_type_string(str, resolved, is_intersection);
12201202
zend_string_release(resolved);

Zend/zend_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ typedef struct {
268268

269269
#define ZEND_TYPE_INIT_CODE(code, allow_null, extra_flags) \
270270
ZEND_TYPE_INIT_MASK(((code) == _IS_BOOL ? MAY_BE_BOOL : ( (code) == IS_ITERABLE ? _ZEND_TYPE_ITERABLE_BIT : ((code) == IS_MIXED ? MAY_BE_ANY : (1 << (code))))) \
271-
| ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags)) \
271+
| ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags))
272272

273273
#define ZEND_TYPE_INIT_PTR(ptr, type_kind, allow_null, extra_flags) \
274274
{ (void *) (ptr), \

ext/reflection/php_reflection.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3064,7 +3064,6 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
30643064
reflection_object *intern;
30653065
type_reference *param;
30663066
uint32_t type_mask;
3067-
bool has_iterable = false;
30683067

30693068
if (zend_parse_parameters_none() == FAILURE) {
30703069
RETURN_THROWS();
@@ -3075,10 +3074,6 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
30753074
if (ZEND_TYPE_HAS_LIST(param->type)) {
30763075
zend_type *list_type;
30773076
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(param->type), list_type) {
3078-
/* BC for iterable type */
3079-
if (UNEXPECTED(ZEND_TYPE_IS_ITERABLE_FALLBACK(*list_type))) {
3080-
has_iterable = true;
3081-
}
30823077
append_type(return_value, *list_type);
30833078
} ZEND_TYPE_LIST_FOREACH_END();
30843079
} else if (ZEND_TYPE_HAS_NAME(param->type)) {
@@ -3098,7 +3093,7 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
30983093
if (type_mask & MAY_BE_OBJECT) {
30993094
append_type_mask(return_value, MAY_BE_OBJECT);
31003095
}
3101-
if ((type_mask & MAY_BE_ARRAY) && !has_iterable) {
3096+
if ((type_mask & MAY_BE_ARRAY)) {
31023097
append_type_mask(return_value, MAY_BE_ARRAY);
31033098
}
31043099
if (type_mask & MAY_BE_STRING) {

ext/reflection/tests/ReflectionType_001.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ class PropTypeTest {
8080
public int $int;
8181
public string $string;
8282
public array $arr;
83-
public iterable $iterable;
8483
public stdClass $std;
8584
public OtherThing $other;
8685
public $mixed;
@@ -216,7 +215,6 @@ string(4) "Test"
216215
public int $int;
217216
public string $string;
218217
public array $arr;
219-
public iterable $iterable;
220218
public stdClass $std;
221219
public OtherThing $other;
222220
public $mixed;

ext/reflection/tests/ReflectionType_possible_types.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ $functions = [
1111
function(): bool {},
1212
function(): array {},
1313
function(): callable {},
14-
function(): iterable {},
1514
function(): null {},
1615
function(): false {},
1716
function(): StdClass {}
@@ -31,7 +30,6 @@ string(6) "string"
3130
string(4) "bool"
3231
string(5) "array"
3332
string(8) "callable"
34-
string(8) "iterable"
3533
string(4) "null"
3634
string(5) "false"
3735
string(8) "StdClass"

ext/reflection/tests/bug72661.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ function test(iterable $arg) { }
77
var_dump((string)(new ReflectionParameter("test", 0))->getType());
88
?>
99
--EXPECT--
10-
string(8) "iterable"
10+
string(17) "Traversable|array"

0 commit comments

Comments
 (0)