diff --git a/Zend/tests/return_types/rfc002.phpt b/Zend/tests/return_types/rfc002.phpt index 29b5ed3220fc1..7bc95e74527b7 100644 --- a/Zend/tests/return_types/rfc002.phpt +++ b/Zend/tests/return_types/rfc002.phpt @@ -8,6 +8,7 @@ function answer(): int { } answer(); - ---EXPECTF-- -Catchable fatal error: Return value of answer() must be an instance of int, integer returned in %s on line %d +?> +DONE +--EXPECT-- +DONE diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 693a8340f8ccc..f40a403353a1e 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -164,6 +164,7 @@ ZEND_API char *zend_get_type_by_const(int type) /* {{{ */ switch(type) { case IS_FALSE: case IS_TRUE: + case _IS_BOOL: return "boolean"; case IS_LONG: return "integer"; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 1a716080838e7..fe55b9189f96d 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1871,7 +1871,11 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */ static void zend_emit_return_type_check(znode *expr, zend_arg_info *return_info) /* {{{ */ { if (return_info->type_hint != IS_UNDEF) { - zend_emit_op(NULL, ZEND_VERIFY_RETURN_TYPE, expr, NULL); + zend_op *opline = zend_emit_op(NULL, ZEND_VERIFY_RETURN_TYPE, expr, NULL); + if (expr && expr->op_type == IS_CONST) { + opline->result_type = expr->op_type = IS_TMP_VAR; + opline->result.var = expr->u.op.var = get_temporary_variable(CG(active_op_array)); + } } } /* }}} */ @@ -3288,10 +3292,7 @@ void zend_compile_return(zend_ast *ast) /* {{{ */ } if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { - zend_emit_return_type_check(&expr_node, CG(active_op_array)->arg_info - 1); - if (expr_node.op_type == IS_CONST) { - zval_copy_ctor(&expr_node.u.constant); - } + zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1); } opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN, &expr_node, NULL); @@ -3927,6 +3928,25 @@ void zend_compile_stmt_list(zend_ast *ast) /* {{{ */ } /* }}} */ +static int zend_scalar_type_hint(zend_string *type_name, zend_arg_info *arg_info) /* {{{ */ +{ + if (zend_string_equals_literal_ci(type_name, "bool")) { + arg_info->type_hint = _IS_BOOL; + } else if (zend_string_equals_literal_ci(type_name, "int")) { + arg_info->type_hint = IS_LONG; + } else if (zend_string_equals_literal_ci(type_name, "float")) { + arg_info->type_hint = IS_DOUBLE; + } else if (zend_string_equals_literal_ci(type_name, "string")) { + arg_info->type_hint = IS_STRING; + } else if (zend_string_equals_literal_ci(type_name, "resource")) { + arg_info->type_hint = IS_RESOURCE; + } else { + return 0; + } + return 1; +} +/* }}} */ + void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_method) /* {{{ */ { zend_ast_list *list = zend_ast_get_list(ast); @@ -3949,18 +3969,20 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_ } else { zend_string *class_name = zend_ast_get_str(return_type_ast); - if (zend_is_const_default_class_ref(return_type_ast)) { - class_name = zend_resolve_class_name_ast(return_type_ast); - } else { - zend_string_addref(class_name); - if (!is_method) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare a return type of %s outside of a class scope", class_name->val); - return; + if (!zend_scalar_type_hint(class_name, arg_infos)) { + if (zend_is_const_default_class_ref(return_type_ast)) { + class_name = zend_resolve_class_name_ast(return_type_ast); + } else { + zend_string_addref(class_name); + if (!is_method) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare a return type of %s outside of a class scope", class_name->val); + return; + } } - } - arg_infos->type_hint = IS_OBJECT; - arg_infos->class_name = class_name; + arg_infos->type_hint = IS_OBJECT; + arg_infos->class_name = class_name; + } } arg_infos++; @@ -4052,6 +4074,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_ op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; arg_info->allow_null = has_null_default; + if (type_ast->kind == ZEND_AST_TYPE) { arg_info->type_hint = type_ast->attr; if (arg_info->type_hint == IS_ARRAY) { @@ -4071,18 +4094,26 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_ } else { zend_string *class_name = zend_ast_get_str(type_ast); - if (zend_is_const_default_class_ref(type_ast)) { - class_name = zend_resolve_class_name_ast(type_ast); + if (zend_scalar_type_hint(class_name, arg_info)) { + if (default_ast && !has_null_default && !Z_CONSTANT(default_node.u.constant) && + Z_TYPE(default_node.u.constant) != arg_info->type_hint) { + zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " + "with a %s type hint can only be %s or NULL", class_name->val, class_name->val); + } } else { - zend_string_addref(class_name); - } + if (zend_is_const_default_class_ref(type_ast)) { + class_name = zend_resolve_class_name_ast(type_ast); + } else { + zend_string_addref(class_name); + } - arg_info->type_hint = IS_OBJECT; - arg_info->class_name = class_name; + arg_info->type_hint = IS_OBJECT; + arg_info->class_name = class_name; - if (default_ast && !has_null_default && !Z_CONSTANT(default_node.u.constant)) { + if (default_ast && !has_null_default && !Z_CONSTANT(default_node.u.constant)) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " "with a class type hint can only be NULL"); + } } } } diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 6d679f0563162..8f76985a9e7d1 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -527,6 +527,57 @@ static inline int make_real_object(zval *object) return 1; } +static int zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg) +{ + switch (type_hint) { + case _IS_BOOL: { + zend_bool dest; + + if (Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE) { + return 1; + } + if (!zend_parse_arg_bool(arg, &dest, NULL, 0)) { + return 0; + } + zval_ptr_dtor(arg); + ZVAL_BOOL(arg, dest); + return 1; + } + case IS_LONG: { + zend_long dest; + + if (!zend_parse_arg_long(arg, &dest, NULL, 0, 0)) { + return 0; + } + zval_ptr_dtor(arg); + ZVAL_LONG(arg, dest); + return 1; + } + case IS_DOUBLE: { + double dest; + + if (!zend_parse_arg_double(arg, &dest, NULL, 0)) { + return 0; + } + zval_ptr_dtor(arg); + ZVAL_DOUBLE(arg, dest); + return 1; + } + case IS_STRING: { + zend_string *dest; + + /* on success "arg" is converted to IS_STRING */ + if (!zend_parse_arg_str(arg, &dest, 0)) { + return 0; + } + return 1; + } + case IS_RESOURCE: + default: + return 0; + } +} + ZEND_API char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce) { zend_string *key; @@ -610,7 +661,7 @@ static int is_null_constant(zval *default_value) static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg) { zend_internal_arg_info *cur_arg_info; - char *need_msg; + char *need_msg, *class_name; zend_class_entry *ce; if (EXPECTED(arg_num <= zf->internal_function.num_args)) { @@ -621,33 +672,26 @@ static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, z return; } - if (cur_arg_info->class_name) { - char *class_name; - + if (cur_arg_info->type_hint) { ZVAL_DEREF(arg); - if (Z_TYPE_P(arg) == IS_OBJECT) { - need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce); - if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg); + if (EXPECTED(cur_arg_info->type_hint == Z_TYPE_P(arg))) { + if (cur_arg_info->class_name) { + need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce); + if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) { + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg); + } } } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) { - need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce); - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg); - } - } else if (cur_arg_info->type_hint) { - if (cur_arg_info->type_hint == IS_ARRAY) { - ZVAL_DEREF(arg); - if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg); - } - } else if (cur_arg_info->type_hint == IS_CALLABLE) { - if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg); + if (cur_arg_info->class_name) { + need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg); + } else if (cur_arg_info->type_hint == IS_CALLABLE) { + if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) { + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg); + } + } else if (!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg)) { + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg); } -#if ZEND_DEBUG - } else { - zend_error(E_ERROR, "Unknown typehint"); -#endif } } } @@ -655,7 +699,7 @@ static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, z static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value) { zend_arg_info *cur_arg_info; - char *need_msg; + char *need_msg, *class_name; zend_class_entry *ce; if (EXPECTED(arg_num <= zf->common.num_args)) { @@ -666,33 +710,26 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, return; } - if (cur_arg_info->class_name) { - char *class_name; - + if (cur_arg_info->type_hint) { ZVAL_DEREF(arg); - if (Z_TYPE_P(arg) == IS_OBJECT) { - need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce); - if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg); + if (EXPECTED(cur_arg_info->type_hint == Z_TYPE_P(arg))) { + if (cur_arg_info->class_name) { + need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce); + if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) { + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg); + } } } else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value)))) { - need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce); - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg); - } - } else if (cur_arg_info->type_hint) { - if (cur_arg_info->type_hint == IS_ARRAY) { - ZVAL_DEREF(arg); - if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg); - } - } else if (cur_arg_info->type_hint == IS_CALLABLE) { - if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg); + if (cur_arg_info->class_name) { + need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg); + } else if (cur_arg_info->type_hint == IS_CALLABLE) { + if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) { + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg); + } + } else if (!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg)) { + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg); } -#if ZEND_DEBUG - } else { - zend_error(E_ERROR, "Unknown typehint"); -#endif } } } @@ -700,7 +737,7 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num) { zend_arg_info *cur_arg_info; - char *need_msg; + char *need_msg, *class_name; zend_class_entry *ce; if (EXPECTED(arg_num <= zf->common.num_args)) { @@ -711,21 +748,14 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n return 1; } - if (cur_arg_info->class_name) { - char *class_name; - - need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce); - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "", NULL); - return 0; - } else if (cur_arg_info->type_hint) { - if (cur_arg_info->type_hint == IS_ARRAY) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "", NULL); - } else if (cur_arg_info->type_hint == IS_CALLABLE) { + if (cur_arg_info->type_hint) { + if (cur_arg_info->class_name) { + need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "", NULL); + } else if (cur_arg_info->type_hint == IS_CALLABLE) { zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "", NULL); -#if ZEND_DEBUG } else { - zend_error(E_ERROR, "Unknown typehint"); -#endif + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), "none", "", NULL); } return 0; } @@ -772,39 +802,32 @@ ZEND_API void zend_verify_return_error(int error_type, const zend_function *zf, static int zend_verify_internal_return_type(zend_function *zf, zval *ret) { zend_arg_info *ret_info = zf->common.arg_info - 1; - char *need_msg; + char *need_msg, *class_name; zend_class_entry *ce; - if (ret_info->class_name) { - char *class_name; - - if (Z_TYPE_P(ret) == IS_OBJECT) { - need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce); - if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) { - zend_verify_return_error(E_CORE_ERROR, zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val); - return 0; + if (ret_info->type_hint) { + if (EXPECTED(ret_info->type_hint == Z_TYPE_P(ret))) { + if (ret_info->class_name) { + need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce); + if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) { + zend_verify_return_error(E_CORE_ERROR, zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val); + return 0; + } } } else if (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null) { - need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce); - zend_verify_return_error(E_CORE_ERROR, zf, need_msg, class_name, zend_zval_type_name(ret), ""); - return 0; - } - } else if (ret_info->type_hint) { - if (ret_info->type_hint == IS_ARRAY) { - if (Z_TYPE_P(ret) != IS_ARRAY && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) { - zend_verify_return_error(E_CORE_ERROR, zf, "be of the type array", "", zend_zval_type_name(ret), ""); + if (ret_info->class_name) { + need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce); + zend_verify_return_error(E_CORE_ERROR, zf, need_msg, class_name, zend_zval_type_name(ret), ""); return 0; - } - } else if (ret_info->type_hint == IS_CALLABLE) { - if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) { - zend_verify_return_error(E_CORE_ERROR, zf, "be callable", "", zend_zval_type_name(ret), ""); + } else if (ret_info->type_hint == IS_CALLABLE) { + if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL)) { + zend_verify_return_error(E_CORE_ERROR, zf, "be callable", "", zend_zval_type_name(ret), ""); + return 0; + } + } else if (!zend_verify_scalar_type_hint(ret_info->type_hint, ret)) { + zend_verify_return_error(E_CORE_ERROR, zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), ""); return 0; } -#if ZEND_DEBUG - } else { - zend_error(E_CORE_ERROR, "Unknown typehint"); - return 0; -#endif } } return 1; @@ -814,34 +837,28 @@ static int zend_verify_internal_return_type(zend_function *zf, zval *ret) static void zend_verify_return_type(zend_function *zf, zval *ret) { zend_arg_info *ret_info = zf->common.arg_info - 1; - char *need_msg; + char *need_msg, *class_name; zend_class_entry *ce; - if (ret_info->class_name) { - char *class_name; - - if (Z_TYPE_P(ret) == IS_OBJECT) { - need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce); - if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) { - zend_verify_return_error(E_RECOVERABLE_ERROR, zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val); + if (ret_info->type_hint) { + if (EXPECTED(ret_info->type_hint == Z_TYPE_P(ret))) { + if (ret_info->class_name) { + need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce); + if (!ce || !instanceof_function(Z_OBJCE_P(ret), ce)) { + zend_verify_return_error(E_RECOVERABLE_ERROR, zf, need_msg, class_name, "instance of ", Z_OBJCE_P(ret)->name->val); + } } } else if (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null) { - need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce); - zend_verify_return_error(E_RECOVERABLE_ERROR, zf, need_msg, class_name, zend_zval_type_name(ret), ""); - } - } else if (ret_info->type_hint) { - if (ret_info->type_hint == IS_ARRAY) { - if (Z_TYPE_P(ret) != IS_ARRAY && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) { - zend_verify_return_error(E_RECOVERABLE_ERROR, zf, "be of the type array", "", zend_zval_type_name(ret), ""); - } - } else if (ret_info->type_hint == IS_CALLABLE) { - if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) { - zend_verify_return_error(E_RECOVERABLE_ERROR, zf, "be callable", "", zend_zval_type_name(ret), ""); + if (ret_info->class_name) { + need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce); + zend_verify_return_error(E_RECOVERABLE_ERROR, zf, need_msg, class_name, zend_zval_type_name(ret), ""); + } else if (ret_info->type_hint == IS_CALLABLE) { + if (!zend_is_callable(ret, IS_CALLABLE_CHECK_SILENT, NULL)) { + zend_verify_return_error(E_RECOVERABLE_ERROR, zf, "be callable", "", zend_zval_type_name(ret), ""); + } + } else if (!zend_verify_scalar_type_hint(ret_info->type_hint, ret)) { + zend_verify_return_error(E_RECOVERABLE_ERROR, zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), ""); } -#if ZEND_DEBUG - } else { - zend_error(E_ERROR, "Unknown typehint"); -#endif } } } @@ -849,24 +866,17 @@ static void zend_verify_return_type(zend_function *zf, zval *ret) static inline int zend_verify_missing_return_type(zend_function *zf) { zend_arg_info *ret_info = zf->common.arg_info - 1; - char *need_msg; + char *need_msg, *class_name; zend_class_entry *ce; - if (ret_info->class_name) { - char *class_name; - - need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce); - zend_verify_return_error(E_RECOVERABLE_ERROR, zf, need_msg, class_name, "none", ""); - return 0; - } else if (ret_info->type_hint) { - if (ret_info->type_hint == IS_ARRAY) { - zend_verify_return_error(E_RECOVERABLE_ERROR, zf, "be of the type array", "", "none", ""); + if (ret_info->type_hint) { + if (ret_info->class_name) { + need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce); + zend_verify_return_error(E_RECOVERABLE_ERROR, zf, need_msg, class_name, "none", ""); } else if (ret_info->type_hint == IS_CALLABLE) { zend_verify_return_error(E_RECOVERABLE_ERROR, zf, "be callable", "", "none", ""); -#if ZEND_DEBUG } else { - zend_error(E_ERROR, "Unknown typehint"); -#endif + zend_verify_return_error(E_RECOVERABLE_ERROR, zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), "none", ""); } return 0; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 33760decf5822..15bd60884aab0 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3198,9 +3198,8 @@ ZEND_VM_C_LABEL(fcall_end): ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED) { -#if OP1_TYPE != IS_UNUSED USE_OPLINE -#endif + SAVE_OPLINE(); if (OP1_TYPE == IS_UNUSED) { zend_verify_missing_return_type(EX(func)); @@ -3210,6 +3209,9 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED) retval_ptr = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); zend_verify_return_type(EX(func), retval_ptr); + if (OP1_TYPE == IS_CONST) { + ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr); + } } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 5832af633a7e9..f2e1c48dc06b9 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -6358,9 +6358,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER static int ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { -#if IS_CONST != IS_UNUSED USE_OPLINE -#endif + SAVE_OPLINE(); if (IS_CONST == IS_UNUSED) { zend_verify_missing_return_type(EX(func)); @@ -6370,6 +6369,9 @@ static int ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_UNUSED_HANDLER(ZEND retval_ptr = EX_CONSTANT(opline->op1); zend_verify_return_type(EX(func), retval_ptr); + if (IS_CONST == IS_CONST) { + ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr); + } } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -10485,9 +10487,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_UNUSED_HANDLER(ZEND_O static int ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { -#if IS_TMP_VAR != IS_UNUSED USE_OPLINE -#endif + SAVE_OPLINE(); if (IS_TMP_VAR == IS_UNUSED) { zend_verify_missing_return_type(EX(func)); @@ -10497,6 +10498,9 @@ static int ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UNUSED_HANDLER(ZEND_O retval_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); zend_verify_return_type(EX(func), retval_ptr); + if (IS_TMP_VAR == IS_CONST) { + ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr); + } } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -15555,9 +15559,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z static int ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { -#if IS_VAR != IS_UNUSED USE_OPLINE -#endif + SAVE_OPLINE(); if (IS_VAR == IS_UNUSED) { zend_verify_missing_return_type(EX(func)); @@ -15567,6 +15570,9 @@ static int ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UNUSED_HANDLER(ZEND_O retval_ptr = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1); zend_verify_return_type(EX(func), retval_ptr); + if (IS_VAR == IS_CONST) { + ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr); + } } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -20885,9 +20891,8 @@ static int ZEND_FASTCALL ZEND_ASSIGN_BW_XOR_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPC static int ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { -#if IS_UNUSED != IS_UNUSED USE_OPLINE -#endif + SAVE_OPLINE(); if (IS_UNUSED == IS_UNUSED) { zend_verify_missing_return_type(EX(func)); @@ -20897,6 +20902,9 @@ static int ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED_UNUSED_HANDLER(ZEN retval_ptr = NULL; zend_verify_return_type(EX(func), retval_ptr); + if (IS_UNUSED == IS_CONST) { + ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr); + } } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -29236,9 +29244,8 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HAN static int ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { -#if IS_CV != IS_UNUSED USE_OPLINE -#endif + SAVE_OPLINE(); if (IS_CV == IS_UNUSED) { zend_verify_missing_return_type(EX(func)); @@ -29248,6 +29255,9 @@ static int ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNUSED_HANDLER(ZEND_OP retval_ptr = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var); zend_verify_return_type(EX(func), retval_ptr); + if (IS_CV == IS_CONST) { + ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr); + } } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE();