diff --git a/Zend/tests/magic_methods/magic_methods_021.phpt b/Zend/tests/magic_methods/magic_methods_021.phpt index fd3e7fa9d0ee5..33a7220e5674e 100644 --- a/Zend/tests/magic_methods/magic_methods_021.phpt +++ b/Zend/tests/magic_methods/magic_methods_021.phpt @@ -12,7 +12,7 @@ class Foo2 { } class Foo3 { - public static function __set_state(array $data): Foo3|self {} + public static function __set_state(array $data): Foo3|Foo2 {} } ?> diff --git a/Zend/tests/type_declarations/intersection_types/relative_types/relative_parent_type_is_allow_when_compile_time_resolve.phpt b/Zend/tests/type_declarations/intersection_types/relative_types/relative_parent_type_is_allow_when_compile_time_resolve.phpt new file mode 100644 index 0000000000000..09deba14dc15b --- /dev/null +++ b/Zend/tests/type_declarations/intersection_types/relative_types/relative_parent_type_is_allow_when_compile_time_resolve.phpt @@ -0,0 +1,15 @@ +--TEST-- +parent type can take part in an intersection type is resolvable at compile time +--FILE-- + +DONE +--EXPECT-- +DONE diff --git a/Zend/tests/type_declarations/intersection_types/invalid_types/invalid_parent_type.phpt b/Zend/tests/type_declarations/intersection_types/relative_types/relative_parent_type_is_not_allow_if_not_compile_time_resolve.phpt similarity index 62% rename from Zend/tests/type_declarations/intersection_types/invalid_types/invalid_parent_type.phpt rename to Zend/tests/type_declarations/intersection_types/relative_types/relative_parent_type_is_not_allow_if_not_compile_time_resolve.phpt index e3a86771a2189..9ff858deb0da7 100644 --- a/Zend/tests/type_declarations/intersection_types/invalid_types/invalid_parent_type.phpt +++ b/Zend/tests/type_declarations/intersection_types/relative_types/relative_parent_type_is_not_allow_if_not_compile_time_resolve.phpt @@ -1,14 +1,13 @@ --TEST-- -parent type cannot take part in an intersection type +parent type cannot take part in an intersection type if not resolvable at compile time --FILE-- +DONE --EXPECTF-- Fatal error: Type parent cannot be part of an intersection type in %s on line %d diff --git a/Zend/tests/type_declarations/intersection_types/relative_types/relative_parent_type_is_not_allow_if_not_compile_time_resolve2.phpt b/Zend/tests/type_declarations/intersection_types/relative_types/relative_parent_type_is_not_allow_if_not_compile_time_resolve2.phpt new file mode 100644 index 0000000000000..c511a1739ae1c --- /dev/null +++ b/Zend/tests/type_declarations/intersection_types/relative_types/relative_parent_type_is_not_allow_if_not_compile_time_resolve2.phpt @@ -0,0 +1,13 @@ +--TEST-- +parent type cannot take part in an intersection type if not resolvable at compile time +--FILE-- + +DONE +--EXPECTF-- +Fatal error: Type PARENT cannot be part of an intersection type in %s on line %d diff --git a/Zend/tests/type_declarations/intersection_types/relative_types/relative_self_type_is_allow_when_compile_time_resolve.phpt b/Zend/tests/type_declarations/intersection_types/relative_types/relative_self_type_is_allow_when_compile_time_resolve.phpt new file mode 100644 index 0000000000000..707acac144d2c --- /dev/null +++ b/Zend/tests/type_declarations/intersection_types/relative_types/relative_self_type_is_allow_when_compile_time_resolve.phpt @@ -0,0 +1,13 @@ +--TEST-- +self type can take part in an intersection type is resolvable at compile time +--FILE-- + +DONE +--EXPECT-- +DONE diff --git a/Zend/tests/type_declarations/intersection_types/invalid_types/invalid_self_type.phpt b/Zend/tests/type_declarations/intersection_types/relative_types/relative_self_type_is_not_allow_if_not_compile_time_resolve.phpt similarity index 62% rename from Zend/tests/type_declarations/intersection_types/invalid_types/invalid_self_type.phpt rename to Zend/tests/type_declarations/intersection_types/relative_types/relative_self_type_is_not_allow_if_not_compile_time_resolve.phpt index 66c7ec79325dc..69bd437a0743c 100644 --- a/Zend/tests/type_declarations/intersection_types/invalid_types/invalid_self_type.phpt +++ b/Zend/tests/type_declarations/intersection_types/relative_types/relative_self_type_is_not_allow_if_not_compile_time_resolve.phpt @@ -1,12 +1,13 @@ --TEST-- -self type cannot take part in an intersection type +self type cannot take part in an intersection type if not resolvable at compile time --FILE-- +DONE --EXPECTF-- Fatal error: Type self cannot be part of an intersection type in %s on line %d diff --git a/Zend/tests/type_declarations/intersection_types/relative_types/relative_self_type_is_not_allow_if_not_compile_time_resolve2.phpt b/Zend/tests/type_declarations/intersection_types/relative_types/relative_self_type_is_not_allow_if_not_compile_time_resolve2.phpt new file mode 100644 index 0000000000000..00a2127273f2a --- /dev/null +++ b/Zend/tests/type_declarations/intersection_types/relative_types/relative_self_type_is_not_allow_if_not_compile_time_resolve2.phpt @@ -0,0 +1,13 @@ +--TEST-- +self type cannot take part in an intersection type if not resolvable at compile time +--FILE-- + +DONE +--EXPECTF-- +Fatal error: Type SELF cannot be part of an intersection type in %s on line %d diff --git a/Zend/tests/type_declarations/union_types/redundant_types/duplicate_case_sensitive_relative_class_parent_type.phpt b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_case_sensitive_relative_class_parent_type.phpt new file mode 100644 index 0000000000000..3bcd9221f5e28 --- /dev/null +++ b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_case_sensitive_relative_class_parent_type.phpt @@ -0,0 +1,15 @@ +--TEST-- +Duplicate parent type in different cases +--FILE-- + +--EXPECTF-- +Fatal error: Duplicate type Foo is redundant in %s on line %d diff --git a/Zend/tests/type_declarations/union_types/redundant_types/duplicate_case_sensitive_relative_class_self_type.phpt b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_case_sensitive_relative_class_self_type.phpt new file mode 100644 index 0000000000000..ce969e4dca9fc --- /dev/null +++ b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_case_sensitive_relative_class_self_type.phpt @@ -0,0 +1,12 @@ +--TEST-- +Duplicate self type in different cases +--FILE-- + +--EXPECTF-- +Fatal error: Duplicate type Foo is redundant in %s on line %d diff --git a/Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_parent_type.phpt b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_parent_type.phpt new file mode 100644 index 0000000000000..2312fed21e9e6 --- /dev/null +++ b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_parent_type.phpt @@ -0,0 +1,15 @@ +--TEST-- +Duplicate parent type +--FILE-- + +--EXPECTF-- +Fatal error: Duplicate type Foo is redundant in %s on line %d diff --git a/Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_self_type.phpt b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_self_type.phpt new file mode 100644 index 0000000000000..fd3d073f97ba4 --- /dev/null +++ b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_self_type.phpt @@ -0,0 +1,12 @@ +--TEST-- +Duplicate self type +--FILE-- + +--EXPECTF-- +Fatal error: Duplicate type Foo is redundant in %s on line %d diff --git a/Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_static_type.phpt b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_static_type.phpt new file mode 100644 index 0000000000000..9c6e37ca6e093 --- /dev/null +++ b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_static_type.phpt @@ -0,0 +1,12 @@ +--TEST-- +Duplicate static type +--FILE-- + +--EXPECTF-- +Fatal error: Duplicate type static is redundant in %s on line %d diff --git a/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation1.phpt b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation1.phpt new file mode 100644 index 0000000000000..46bdd1c04556b --- /dev/null +++ b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation1.phpt @@ -0,0 +1,13 @@ +--TEST-- +Relative class type self resolving to an existing entry (after variation) +--FILE-- + +DONE +--EXPECTF-- +Fatal error: Duplicate type Foo is redundant in %s on line %d diff --git a/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation2.phpt b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation2.phpt new file mode 100644 index 0000000000000..512f7d6463d93 --- /dev/null +++ b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation2.phpt @@ -0,0 +1,13 @@ +--TEST-- +Relative class type self resolving to an existing entry (before variation) +--FILE-- + +DONE +--EXPECTF-- +Fatal error: Duplicate type Foo is redundant in %s on line %d diff --git a/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation3.phpt b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation3.phpt new file mode 100644 index 0000000000000..930b3116d756b --- /dev/null +++ b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation3.phpt @@ -0,0 +1,16 @@ +--TEST-- +Relative class type parent resolving to an existing entry (after variation) +--FILE-- + +DONE +--EXPECTF-- +Fatal error: Duplicate type Foo is redundant in %s on line %d diff --git a/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation4.phpt b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation4.phpt new file mode 100644 index 0000000000000..dcc3e428641d6 --- /dev/null +++ b/Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation4.phpt @@ -0,0 +1,16 @@ +--TEST-- +Relative class type parent resolving to an existing entry (before variation) +--FILE-- + +DONE +--EXPECTF-- +Fatal error: Duplicate type Foo is redundant in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index cb64729806a23..797ed8cdb08c4 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1409,10 +1409,8 @@ static zend_string *add_intersection_type(zend_string *str, ZEND_TYPE_LIST_FOREACH(intersection_type_list, single_type) { ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*single_type)); ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*single_type)); - zend_string *name = ZEND_TYPE_NAME(*single_type); - zend_string *resolved = resolve_class_name(name, scope); - intersection_str = add_type_string(intersection_str, resolved, /* is_intersection */ true); - zend_string_release(resolved); + + intersection_str = add_type_string(intersection_str, ZEND_TYPE_NAME(*single_type), /* is_intersection */ true); } ZEND_TYPE_LIST_FOREACH_END(); ZEND_ASSERT(intersection_str); @@ -1444,6 +1442,7 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop } ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type)); ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type)); + zend_string *name = ZEND_TYPE_NAME(*list_type); zend_string *resolved = resolve_class_name(name, scope); str = add_type_string(str, resolved, /* is_intersection */ false); @@ -6957,14 +6956,14 @@ static zend_type zend_compile_single_typename(zend_ast *ast) return (zend_type) ZEND_TYPE_INIT_CODE(ast->attr, 0, 0); } else { - zend_string *class_name = zend_ast_get_str(ast); - uint8_t type_code = zend_lookup_builtin_type_by_name(class_name); + zend_string *type_name = zend_ast_get_str(ast); + uint8_t type_code = zend_lookup_builtin_type_by_name(type_name); if (type_code != 0) { if ((ast->attr & ZEND_NAME_NOT_FQ) != ZEND_NAME_NOT_FQ) { zend_error_noreturn(E_COMPILE_ERROR, "Type declaration '%s' must be unqualified", - ZSTR_VAL(zend_string_tolower(class_name))); + ZSTR_VAL(zend_string_tolower(type_name))); } /* Transform iterable into a type union alias */ @@ -6978,38 +6977,55 @@ static zend_type zend_compile_single_typename(zend_ast *ast) return (zend_type) ZEND_TYPE_INIT_CODE(type_code, 0, 0); } else { const char *correct_name; - zend_string *orig_name = zend_ast_get_str(ast); uint32_t fetch_type = zend_get_class_fetch_type_ast(ast); + zend_string *class_name = type_name; + if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) { class_name = zend_resolve_class_name_ast(ast); zend_assert_valid_class_name(class_name, "a type name"); } else { + ZEND_ASSERT(fetch_type == ZEND_FETCH_CLASS_SELF || fetch_type == ZEND_FETCH_CLASS_PARENT); + zend_ensure_valid_class_fetch_type(fetch_type); + if (fetch_type == ZEND_FETCH_CLASS_SELF) { + /* Scope might be unknown for unbound closures and traits */ + if (zend_is_scope_known()) { + class_name = CG(active_class_entry)->name; + ZEND_ASSERT(class_name && "must know class name when resolving self type at compile time"); + } + } else { + ZEND_ASSERT(fetch_type == ZEND_FETCH_CLASS_PARENT); + /* Scope might be unknown for unbound closures and traits */ + if (zend_is_scope_known()) { + class_name = CG(active_class_entry)->parent_name; + ZEND_ASSERT(class_name && "must know class name when resolving parent type at compile time"); + } + } zend_string_addref(class_name); } if (ast->attr == ZEND_NAME_NOT_FQ - && zend_is_confusable_type(orig_name, &correct_name) - && zend_is_not_imported(orig_name)) { + && zend_is_confusable_type(type_name, &correct_name) + && zend_is_not_imported(type_name)) { const char *extra = FC(current_namespace) ? " or import the class with \"use\"" : ""; if (correct_name) { zend_error(E_COMPILE_WARNING, "\"%s\" will be interpreted as a class name. Did you mean \"%s\"? " "Write \"\\%s\"%s to suppress this warning", - ZSTR_VAL(orig_name), correct_name, ZSTR_VAL(class_name), extra); + ZSTR_VAL(type_name), correct_name, ZSTR_VAL(class_name), extra); } else { zend_error(E_COMPILE_WARNING, "\"%s\" is not a supported builtin type " "and will be interpreted as a class name. " "Write \"\\%s\"%s to suppress this warning", - ZSTR_VAL(orig_name), ZSTR_VAL(class_name), extra); + ZSTR_VAL(type_name), ZSTR_VAL(class_name), extra); } } class_name = zend_new_interned_string(class_name); zend_alloc_ce_cache(class_name); - return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, 0, 0); + return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, /* allow null */ false, 0); } } } @@ -7132,6 +7148,7 @@ static zend_type zend_compile_typename_ex( /* Switch from single name to name list. */ type_list->num_types = 1; type_list->types[0] = type; + /* Clear MAY_BE_* type flags */ ZEND_TYPE_FULL_MASK(type_list->types[0]) &= ~_ZEND_TYPE_MAY_BE_MASK; } /* Mark type as list type */ @@ -7178,6 +7195,7 @@ static zend_type zend_compile_typename_ex( "Type contains both true and false, bool must be used instead"); } ZEND_TYPE_FULL_MASK(type) |= ZEND_TYPE_PURE_MASK(single_type); + /* Clear MAY_BE_* type flags */ ZEND_TYPE_FULL_MASK(single_type) &= ~_ZEND_TYPE_MAY_BE_MASK; if (ZEND_TYPE_IS_COMPLEX(single_type)) { @@ -7190,6 +7208,7 @@ static zend_type zend_compile_typename_ex( /* Switch from single name to name list. */ type_list->num_types = 1; type_list->types[0] = type; + /* Clear MAY_BE_* type flags */ ZEND_TYPE_FULL_MASK(type_list->types[0]) &= ~_ZEND_TYPE_MAY_BE_MASK; ZEND_TYPE_SET_LIST(type, type_list); } @@ -7253,8 +7272,10 @@ static zend_type zend_compile_typename_ex( zend_string_release_ex(standard_type_str, false); } /* Check for "self" and "parent" too */ - if (zend_string_equals_literal_ci(ZEND_TYPE_NAME(single_type), "self") - || zend_string_equals_literal_ci(ZEND_TYPE_NAME(single_type), "parent")) { + if ( + zend_string_equals_ci(ZEND_TYPE_NAME(single_type), ZSTR_KNOWN(ZEND_STR_SELF)) + || zend_string_equals_ci(ZEND_TYPE_NAME(single_type), ZSTR_KNOWN(ZEND_STR_PARENT)) + ) { zend_error_noreturn(E_COMPILE_ERROR, "Type %s cannot be part of an intersection type", ZSTR_VAL(ZEND_TYPE_NAME(single_type))); } diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 88263d5d7a5d3..e9e2b947a6c91 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -624,6 +624,8 @@ EMPTY_SWITCH_DEFAULT_CASE() _(ZEND_STR_NULL_LOWERCASE, "null") \ _(ZEND_STR_MIXED, "mixed") \ _(ZEND_STR_TRAVERSABLE, "Traversable") \ + _(ZEND_STR_SELF, "self") \ + _(ZEND_STR_PARENT, "parent") \ _(ZEND_STR_SLEEP, "__sleep") \ _(ZEND_STR_WAKEUP, "__wakeup") \ _(ZEND_STR_CASES, "cases") \ diff --git a/ext/reflection/tests/types/ReflectionType_001.phpt b/ext/reflection/tests/types/ReflectionType_001.phpt index 3441878f155d7..33b3bbffac2a8 100644 --- a/ext/reflection/tests/types/ReflectionType_001.phpt +++ b/ext/reflection/tests/types/ReflectionType_001.phpt @@ -166,12 +166,12 @@ string(10) "SplSubject" bool(true) bool(false) bool(false) -string(4) "self" +string(1) "c" ** Method 2 - parameter 0 bool(true) bool(false) bool(false) -string(6) "parent" +string(8) "stdClass" ** Method 3 - parameter 0 bool(true) bool(false) @@ -195,12 +195,12 @@ string(3) "int" bool(true) bool(false) bool(false) -string(4) "self" +string(1) "c" ** Function/method return type 4 bool(true) bool(false) bool(false) -string(6) "parent" +string(8) "stdClass" ** Function/method return type 5 bool(true) bool(false) diff --git a/ext/reflection/tests/bug80190.phpt b/ext/reflection/tests/types/bug80190.phpt similarity index 93% rename from ext/reflection/tests/bug80190.phpt rename to ext/reflection/tests/types/bug80190.phpt index 16f2fbba42729..14fc8f7ddb21f 100644 --- a/ext/reflection/tests/bug80190.phpt +++ b/ext/reflection/tests/types/bug80190.phpt @@ -48,13 +48,13 @@ foreach ((new ReflectionClass(C::class))->getMethods() as $method) { --EXPECT-- C::a() $method->getReturnType() returns ReflectionNamedType - $method->getReturnType()->__toString() returns self + $method->getReturnType()->__toString() returns C C::b() $method->getReturnType() returns ReflectionUnionType - $method->getReturnType()->__toString() returns stdClass|self + $method->getReturnType()->__toString() returns stdClass|C $method->getReturnType()->getTypes() returns an array with 2 element(s) - type(s) in union: ReflectionNamedType(stdClass), ReflectionNamedType(self) + type(s) in union: ReflectionNamedType(stdClass), ReflectionNamedType(C) C::c() $method->getReturnType() returns ReflectionNamedType