Skip to content

Commit 590ee76

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 e7cc738 commit 590ee76

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);
@@ -894,14 +906,18 @@ static zend_type_check_status zend_check_type_slow(
894906
zend_is_callable(arg, callable_check_flag, NULL)) {
895907
return ZEND_TYPE_CHECK_VALID;
896908
}
897-
/* TODO: move to return type check? */
909+
910+
/* Although static is most commonly used as a return type, it can also be used as a class constant type */
898911
if (
899-
(type_mask & MAY_BE_STATIC)
900-
&& scope != NULL
912+
(ZEND_TYPE_FULL_MASK(*type) & MAY_BE_STATIC)
901913
&& Z_TYPE_P(arg) == IS_OBJECT
902-
&& instanceof_function(Z_OBJCE_P(arg), scope)
903914
) {
904-
return ZEND_TYPE_CHECK_VALID;
915+
if (!scope) {
916+
scope = zend_get_called_scope(EG(current_execute_data));
917+
}
918+
if (EXPECTED(scope) && instanceof_function(Z_OBJCE_P(arg), scope)) {
919+
return ZEND_TYPE_CHECK_VALID;
920+
}
905921
}
906922

907923
/* Only scalar types may coerce to other scalar types */
@@ -985,6 +1001,15 @@ static bool zend_check_type_and_coerce_slow(
9851001
return status != ZEND_TYPE_CHECK_INVALID;
9861002
}
9871003

1004+
static bool zend_check_return_type_slow(
1005+
const zend_type *type,
1006+
zval *arg,
1007+
const zend_reference *ref
1008+
) {
1009+
bool strict_types = ZEND_RET_USES_STRICT_TYPES() || (ref && ZEND_REF_HAS_TYPE_SOURCES(ref));
1010+
return zend_check_type_and_coerce(type, arg, NULL, strict_types, 0);
1011+
}
1012+
9881013
ZEND_API bool zend_check_user_type_slow(
9891014
const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type)
9901015
{

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)