Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 766bdfc

Browse files
committed
Prevent associated type from being in a union or intersection type
1 parent 6194356 commit 766bdfc

7 files changed

+89
-8
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Associated type cannot be in intersection (simple intersection with class type)
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
type T;
8+
public function foo(T&Traversable $param): T&Traversable;
9+
}
10+
11+
?>
12+
--EXPECTF--
13+
Fatal error: Associated type cannot be part of an intersection type in %s on line %d
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Associated type cannot be in intersection (DNF type)
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
type T;
8+
public function foo(stdClass|(T&Traversable) $param): stdClass|(T&Traversable);
9+
}
10+
11+
?>
12+
--EXPECTF--
13+
Fatal error: Associated type cannot be part of an intersection type in %s on line %d
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Associated type cannot be in union (simple union with built-in type)
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
type T;
8+
public function foo(T|int $param): T|int;
9+
}
10+
11+
?>
12+
--EXPECTF--
13+
Fatal error: Associated type cannot be part of a union type in %s on line %d
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Associated type cannot be in union (simple union with class type)
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
type T;
8+
public function foo(T|stdClass $param): T|stdClass;
9+
}
10+
11+
?>
12+
--EXPECTF--
13+
Fatal error: Associated type cannot be part of a union type in %s on line %d
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Associated type cannot be in union (DNF type)
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
type T;
8+
public function foo(T|(Traversable&Countable) $param): T|(Traversable&Countable);
9+
}
10+
11+
?>
12+
--EXPECTF--
13+
Fatal error: Associated type cannot be part of a union type in %s on line %d

‎Zend/zend_compile.c‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6966,9 +6966,11 @@ ZEND_API void zend_set_function_arg_flags(zend_function *func) /* {{{ */
69666966

69676967
static zend_type zend_compile_single_typename(zend_ast *ast)
69686968
{
6969+
zend_class_entry *ce = CG(active_class_entry);
6970+
69696971
ZEND_ASSERT(!(ast->attr & ZEND_TYPE_NULLABLE));
69706972
if (ast->kind == ZEND_AST_TYPE) {
6971-
if (ast->attr == IS_STATIC && !CG(active_class_entry) && zend_is_scope_known()) {
6973+
if (ast->attr == IS_STATIC && !ce && zend_is_scope_known()) {
69726974
zend_error_noreturn(E_COMPILE_ERROR,
69736975
"Cannot use \"static\" when no class scope is active");
69746976
}
@@ -6998,25 +7000,29 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
69987000
const char *correct_name;
69997001
uint32_t fetch_type = zend_get_class_fetch_type_ast(ast);
70007002
zend_string *class_name = type_name;
7003+
uint32_t flags = 0;
70017004

70027005
if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
70037006
class_name = zend_resolve_class_name_ast(ast);
70047007
zend_assert_valid_class_name(class_name, "a type name");
7008+
if (ce && ce->associated_types && zend_hash_exists(ce->associated_types, class_name)) {
7009+
flags = _ZEND_TYPE_ASSOCIATED_BIT;
7010+
}
70057011
} else {
70067012
ZEND_ASSERT(fetch_type == ZEND_FETCH_CLASS_SELF || fetch_type == ZEND_FETCH_CLASS_PARENT);
70077013

70087014
zend_ensure_valid_class_fetch_type(fetch_type);
70097015
if (fetch_type == ZEND_FETCH_CLASS_SELF) {
70107016
/* Scope might be unknown for unbound closures and traits */
70117017
if (zend_is_scope_known()) {
7012-
class_name = CG(active_class_entry)->name;
7018+
class_name = ce->name;
70137019
ZEND_ASSERT(class_name && "must know class name when resolving self type at compile time");
70147020
}
70157021
} else {
70167022
ZEND_ASSERT(fetch_type == ZEND_FETCH_CLASS_PARENT);
70177023
/* Scope might be unknown for unbound closures and traits */
70187024
if (zend_is_scope_known()) {
7019-
class_name = CG(active_class_entry)->parent_name;
7025+
class_name = ce->parent_name;
70207026
ZEND_ASSERT(class_name && "must know class name when resolving parent type at compile time");
70217027
}
70227028
}
@@ -7044,7 +7050,7 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
70447050

70457051
class_name = zend_new_interned_string(class_name);
70467052
zend_alloc_ce_cache(class_name);
7047-
return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, /* allow null */ false, 0);
7053+
return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, /* allow null */ false, flags);
70487054
}
70497055
}
70507056
}
@@ -7193,6 +7199,9 @@ static zend_type zend_compile_typename_ex(
71937199
single_type = zend_compile_single_typename(type_ast);
71947200
uint32_t single_type_mask = ZEND_TYPE_PURE_MASK(single_type);
71957201

7202+
if (ZEND_TYPE_IS_ASSOCIATED(single_type)) {
7203+
zend_error_noreturn(E_COMPILE_ERROR, "Associated type cannot be part of a union type");
7204+
}
71967205
if (single_type_mask == MAY_BE_ANY) {
71977206
zend_error_noreturn(E_COMPILE_ERROR, "Type mixed can only be used as a standalone type");
71987207
}
@@ -7275,6 +7284,9 @@ static zend_type zend_compile_typename_ex(
72757284
zend_ast *type_ast = list->child[i];
72767285
zend_type single_type = zend_compile_single_typename(type_ast);
72777286

7287+
if (ZEND_TYPE_IS_ASSOCIATED(single_type)) {
7288+
zend_error_noreturn(E_COMPILE_ERROR, "Associated type cannot be part of an intersection type");
7289+
}
72787290
/* An intersection of union types cannot exist so invalidate it
72797291
* Currently only can happen with iterable getting canonicalized to Traversable|array */
72807292
if (ZEND_TYPE_IS_ITERABLE_FALLBACK(single_type)) {

‎Zend/zend_types.h‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,15 @@ typedef struct {
142142
zend_type types[1];
143143
} zend_type_list;
144144

145-
#define _ZEND_TYPE_EXTRA_FLAGS_SHIFT 25
146-
#define _ZEND_TYPE_MASK ((1u << 25) - 1)
145+
#define _ZEND_TYPE_EXTRA_FLAGS_SHIFT 26
146+
#define _ZEND_TYPE_MASK ((1u << 26) - 1)
147147
/* Only one of these bits may be set. */
148+
#define _ZEND_TYPE_ASSOCIATED_BIT (1u << 25)
148149
#define _ZEND_TYPE_NAME_BIT (1u << 24)
149150
// Used to signify that type.ptr is not a `zend_string*` but a `const char*`,
150151
#define _ZEND_TYPE_LITERAL_NAME_BIT (1u << 23)
151152
#define _ZEND_TYPE_LIST_BIT (1u << 22)
152-
#define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_NAME_BIT|_ZEND_TYPE_LITERAL_NAME_BIT)
153+
#define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_NAME_BIT|_ZEND_TYPE_LITERAL_NAME_BIT|_ZEND_TYPE_ASSOCIATED_BIT)
153154
/* For BC behaviour with iterable type */
154155
#define _ZEND_TYPE_ITERABLE_BIT (1u << 21)
155156
/* Whether the type list is arena allocated */
@@ -167,7 +168,7 @@ typedef struct {
167168
(((t).type_mask & _ZEND_TYPE_MASK) != 0)
168169

169170
/* If a type is complex it means it's either a list with a union or intersection,
170-
* or the void pointer is a class name */
171+
* the void pointer is a class name, or the type is an associated type (which implies it is a name) */
171172
#define ZEND_TYPE_IS_COMPLEX(t) \
172173
((((t).type_mask) & _ZEND_TYPE_KIND_MASK) != 0)
173174

@@ -180,6 +181,9 @@ typedef struct {
180181
#define ZEND_TYPE_HAS_LIST(t) \
181182
((((t).type_mask) & _ZEND_TYPE_LIST_BIT) != 0)
182183

184+
#define ZEND_TYPE_IS_ASSOCIATED(t) \
185+
((((t).type_mask) & _ZEND_TYPE_ASSOCIATED_BIT) != 0)
186+
183187
#define ZEND_TYPE_IS_ITERABLE_FALLBACK(t) \
184188
((((t).type_mask) & _ZEND_TYPE_ITERABLE_BIT) != 0)
185189

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /