Skip to content

Commit c054ad8

Browse files
committed
Allow self and parent to be part of an intersection type
1 parent 8f8df0f commit c054ad8

File tree

4 files changed

+60
-34
lines changed

4 files changed

+60
-34
lines changed

Zend/tests/type_declarations/intersection_types/invalid_types/invalid_parent_type.phpt

Lines changed: 0 additions & 14 deletions
This file was deleted.

Zend/tests/type_declarations/intersection_types/invalid_types/invalid_self_type.phpt

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--TEST--
2+
Using self/parent/static part of an intersection
3+
--FILE--
4+
<?php
5+
6+
interface X {}
7+
interface Y {}
8+
interface Z {}
9+
10+
class A {
11+
public function test(): self&X {
12+
return $this;
13+
}
14+
}
15+
class B extends A implements X {}
16+
class BError extends A {}
17+
18+
class C extends B {
19+
public function parentIntersection(): parent&X {
20+
return new B();
21+
}
22+
}
23+
class D extends B {
24+
public function parentIntersection(): parent&X {
25+
return new A();
26+
}
27+
}
28+
29+
$b = new B();
30+
$be = new BError();
31+
$c = new C();
32+
$d = new D();
33+
34+
// Self tests
35+
var_dump($b->test());
36+
try {
37+
var_dump($be->test());
38+
} catch (\TypeError $e) {
39+
echo $e->getMessage(), PHP_EOL;
40+
}
41+
42+
// Parent tests
43+
var_dump($c->parentIntersection());
44+
try {
45+
var_dump($d->parentIntersection());
46+
} catch (\TypeError $e) {
47+
echo $e->getMessage(), PHP_EOL;
48+
}
49+
50+
?>
51+
--EXPECT--
52+
object(B)#1 (0) {
53+
}
54+
A::test(): Return value must be of type A&X, BError returned
55+
object(B)#6 (0) {
56+
}
57+
D::parentIntersection(): Return value must be of type B&X, A returned

Zend/zend_compile.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6307,6 +6307,7 @@ static zend_type zend_compile_typename(
63076307
zend_ast_list *list = zend_ast_get_list(ast);
63086308
zend_type_list *type_list;
63096309

6310+
// TODO Is this still true if self/parent are accepted?
63106311
/* Allocate the type list directly on the arena as it must be a type
63116312
* list of the same number of elements as the AST list has children */
63126313
type_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(list->children));
@@ -6317,20 +6318,14 @@ static zend_type zend_compile_typename(
63176318
for (uint32_t i = 0; i < list->children; i++) {
63186319
zend_ast *type_ast = list->child[i];
63196320
zend_type single_type = zend_compile_single_typename(type_ast);
6320-
zend_string *standard_type_str = zend_type_to_string(single_type);
63216321

63226322
/* An intersection of standard types cannot exist so invalidate it */
63236323
if (ZEND_TYPE_IS_ONLY_MASK(single_type)) {
6324+
zend_string *standard_type_str = zend_type_to_string(single_type);
63246325
zend_error_noreturn(E_COMPILE_ERROR,
63256326
"Type %s cannot be part of an intersection type", ZSTR_VAL(standard_type_str));
6327+
zend_string_release_ex(standard_type_str, false);
63266328
}
6327-
/* Check for "self" and "parent" too */
6328-
if (zend_string_equals_literal_ci(standard_type_str, "self")
6329-
|| zend_string_equals_literal_ci(standard_type_str, "parent")) {
6330-
zend_error_noreturn(E_COMPILE_ERROR,
6331-
"Type %s cannot be part of an intersection type", ZSTR_VAL(standard_type_str));
6332-
}
6333-
zend_string_release_ex(standard_type_str, false);
63346329

63356330
/* Add type to the type list */
63366331
type_list->types[type_list->num_types++] = single_type;

0 commit comments

Comments
 (0)