Skip to content

Commit b74504e

Browse files
committed
Create a dedicated function for type checking return types
And determine scope for self/parent types rather than determining it in the VM Opcode as this is usually unnecessary
1 parent b84bdd4 commit b74504e

3 files changed

Lines changed: 42 additions & 50 deletions

File tree

Zend/zend_execute.c

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -739,9 +739,21 @@ static const zend_class_entry *resolve_single_class_type(
739739
zend_string *name,
740740
const zend_class_entry *scope) {
741741
if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_SELF))) {
742+
/* We don't fetch the scope in the ZEND_VERIFY_RETURN_TYPE VM opcode, thus fetch it here
743+
* This is an OK tradeoff as for class methods self/parent types are resolved at compile time
744+
* Therefore, we only hit this for trait methods and unbound closures */
745+
if (!scope) {
746+
scope = zend_get_executed_scope();
747+
}
742748
/* If we don't have a scope, returning the NULL pointer is fine as the error handling is done on the call site */
743749
return scope;
744-
} else if (UNEXPECTED(zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_PARENT)))) { // Parent as a type is extremely uncommon
750+
} else if (UNEXPECTED(zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_PARENT)))) { /* Parent as a type is extremely uncommon */
751+
/* We don't fetch the scope in the ZEND_VERIFY_RETURN_TYPE VM opcode, thus fetch it here
752+
* This is an OK tradeoff as for class methods self/parent types are resolved at compile time
753+
* Therefore, we only hit this for trait methods and unbound closures */
754+
if (!scope) {
755+
scope = zend_get_executed_scope();
756+
}
745757
return scope ? scope->parent : NULL;
746758
} else {
747759
return zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT);
@@ -899,14 +911,18 @@ static zend_type_check_status zend_check_type_slow(
899911
zend_is_callable(arg, callable_check_flag, NULL)) {
900912
return ZEND_TYPE_CHECK_VALID;
901913
}
902-
/* TODO: move to return type check? */
914+
915+
/* Although static is most commonly used as a return type, it can also be used as a class constant type */
903916
if (
904-
(type_mask & MAY_BE_STATIC)
905-
&& scope != NULL
917+
(ZEND_TYPE_FULL_MASK(*type) & MAY_BE_STATIC)
906918
&& Z_TYPE_P(arg) == IS_OBJECT
907-
&& instanceof_function(Z_OBJCE_P(arg), scope)
908919
) {
909-
return ZEND_TYPE_CHECK_VALID;
920+
if (!scope) {
921+
scope = zend_get_called_scope(EG(current_execute_data));
922+
}
923+
if (EXPECTED(scope) && instanceof_function(Z_OBJCE_P(arg), scope)) {
924+
return ZEND_TYPE_CHECK_VALID;
925+
}
910926
}
911927

912928
/* Only scalar types may coerce to other scalar types */
@@ -990,6 +1006,15 @@ static bool zend_check_type_and_coerce_slow(
9901006
return status != ZEND_TYPE_CHECK_INVALID;
9911007
}
9921008

1009+
static bool zend_check_return_type_slow(
1010+
const zend_type *type,
1011+
zval *arg,
1012+
const zend_reference *ref
1013+
) {
1014+
bool strict_types = ZEND_RET_USES_STRICT_TYPES() || (ref && ZEND_REF_HAS_TYPE_SOURCES(ref));
1015+
return zend_check_type_and_coerce(type, arg, NULL, strict_types, 0);
1016+
}
1017+
9931018
ZEND_API bool zend_check_user_type_slow(
9941019
const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type)
9951020
{

Zend/zend_vm_def.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4523,10 +4523,7 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
45234523
}
45244524

45254525
SAVE_OPLINE();
4526-
zend_class_entry *scope = Z_TYPE(EX(This)) == IS_OBJECT ? Z_OBJCE(EX(This)) : Z_CE(EX(This));
4527-
bool ref_has_type_sources = ref ? ZEND_REF_HAS_TYPE_SOURCES(ref) : false;
4528-
if (UNEXPECTED(!zend_check_type_and_coerce_slow(&ret_info->type, retval_ptr, scope,
4529-
(EX(func)->op_array.fn_flags & ZEND_ACC_STRICT_TYPES) || ref_has_type_sources, 0))) {
4526+
if (UNEXPECTED(!zend_check_return_type_slow(&ret_info->type, retval_ptr, ref))) {
45304527
zend_verify_return_error(EX(func), retval_ptr);
45314528
HANDLE_EXCEPTION();
45324529
}

Zend/zend_vm_execute.h

Lines changed: 10 additions & 40 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)