summaryrefslogtreecommitdiff
path: root/Zend/zend_execute.c
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-03-21 01:00:00 +0300
committerDmitry Stogov <dmitry@zend.com>2015-03-21 01:00:00 +0300
commit430266edfa93e04cf5199d289050ba14866645b3 (patch)
tree8417c4f5c30fb6da767376d3f6aa568cd3d7ad88 /Zend/zend_execute.c
parenta43a9c91374b3cd9864eea5e7c0b0e2e9dafa2e2 (diff)
parent1f408af03cf5dcfbcabebb20f162d2ed787b5579 (diff)
downloadphp-git-430266edfa93e04cf5199d289050ba14866645b3.tar.gz
Merge branch 'scalar_type_hints_v5'
* scalar_type_hints_v5: (65 commits) Fixed in-place modification of IS_CONST operand Changed SKIPIF messages ZPP changed to lazely check for "strict/weak" only if it's really necessary. Cleanup. cleanup Fixed return type hint handling for constants Fixed tests Imroved ZPP rules (condititins reoredered to prevent duplicate checks) Fixed comments Fixed error messages Improved type hinting: Fixed white spaces Add check for maintaining reference all the way through both type and return values Reduce the number of times that the zval needs to be separated in return type checking to those that are necessary Add test to ensure namespaced code can't use scalar types as class names Disallow relative namespace type declarations Add support and tests for null constant default values. Refactor complex conditionals into an extracted function for clarity and code-reuse Refactor as to not use call info, but add the flag to the op_array. Fix severity issues with callbacks, start work porting ZEND_STRLEN opcode to work with strict mode, more refactoring to come Fix C89 compatibility by moving a misplaced if statement Refactor gotos into more elaborate ifs to eliminate goto failure ...
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r--Zend/zend_execute.c320
1 files changed, 192 insertions, 128 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index caaeb6a5fd..0fe2a26e97 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -598,7 +598,7 @@ ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ch
}
}
-ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg)
+ZEND_API void zend_verify_arg_error(const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg)
{
zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
const char *fname = zf->common.function_name->val;
@@ -621,16 +621,18 @@ ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uin
}
if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
- zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->func->op_array.filename->val, ptr->opline->lineno);
+ zend_type_error("Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d",
+ arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind,
+ ptr->func->op_array.filename->val, ptr->opline->lineno);
} else {
- zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
+ zend_type_error("Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
}
if (arg) {
ZVAL_COPY_VALUE(arg, &old_arg);
}
} else {
- zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
+ zend_type_error("Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
}
}
@@ -649,10 +651,71 @@ static int is_null_constant(zval *default_value)
return 0;
}
+static zend_bool zend_verify_weak_scalar_type_hint(zend_uchar type_hint, zval *arg)
+{
+ switch (type_hint) {
+ case _IS_BOOL: {
+ zend_bool dest;
+
+ if (!zend_parse_arg_bool_weak(arg, &dest)) {
+ return 0;
+ }
+ zval_ptr_dtor(arg);
+ ZVAL_BOOL(arg, dest);
+ return 1;
+ }
+ case IS_LONG: {
+ zend_long dest;
+
+ if (!zend_parse_arg_long_weak(arg, &dest)) {
+ return 0;
+ }
+ zval_ptr_dtor(arg);
+ ZVAL_LONG(arg, dest);
+ return 1;
+ }
+ case IS_DOUBLE: {
+ double dest;
+
+ if (!zend_parse_arg_double_weak(arg, &dest)) {
+ 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_weak(arg, &dest)) {
+ return 0;
+ }
+ return 1;
+ }
+ default:
+ return 0;
+ }
+}
+
+static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg, zend_bool strict)
+{
+ if (UNEXPECTED(strict)) {
+ /* SSTH Exception: IS_LONG may be accepted as IS_DOUBLE (converted) */
+ if (type_hint != IS_DOUBLE || Z_TYPE_P(arg) != IS_LONG) {
+ return 0;
+ }
+ } else if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
+ /* NULL may be accepted only by nullable hints (this is already checked) */
+ return 0;
+ }
+ return zend_verify_weak_scalar_type_hint(type_hint, arg);
+}
+
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)) {
@@ -663,33 +726,29 @@ 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_EXCEPTION | E_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(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_EXCEPTION | E_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_EXCEPTION | E_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_EXCEPTION | E_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(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(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
+ }
+ } else if (cur_arg_info->type_hint == _IS_BOOL &&
+ EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
+ /* pass */
+ } else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
+ zend_verify_arg_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
}
}
}
@@ -697,7 +756,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)) {
@@ -708,33 +767,29 @@ 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_EXCEPTION | E_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(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_EXCEPTION | E_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_EXCEPTION | E_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_EXCEPTION | E_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(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(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
+ }
+ } else if (cur_arg_info->type_hint == _IS_BOOL &&
+ EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
+ /* pass */
+ } else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_ARG_USES_STRICT_TYPES()))) {
+ zend_verify_arg_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
}
}
}
@@ -753,21 +808,17 @@ 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;
+ if (cur_arg_info->type_hint) {
+ 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_EXCEPTION | E_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_EXCEPTION | E_ERROR, zf, arg_num, "be of the type array", "", "none", "", NULL);
+ need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce);
+ zend_verify_arg_error(zf, arg_num, need_msg, class_name, "none", "", NULL);
+ return 0;
} else if (cur_arg_info->type_hint == IS_CALLABLE) {
- zend_verify_arg_error(E_EXCEPTION | E_ERROR, zf, arg_num, "be callable", "", "none", "", NULL);
-#if ZEND_DEBUG
+ zend_verify_arg_error(zf, arg_num, "be callable", "", "none", "", NULL);
} else {
- zend_error(E_ERROR, "Unknown typehint");
-#endif
+ zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), "none", "", NULL);
}
return 0;
}
@@ -791,7 +842,7 @@ static void zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t ar
}
}
-ZEND_API void zend_verify_return_error(int error_type, const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
+ZEND_API void zend_verify_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
{
const char *fname = zf->common.function_name->val;
const char *fsep;
@@ -805,8 +856,31 @@ ZEND_API void zend_verify_return_error(int error_type, const zend_function *zf,
fclass = "";
}
- zend_error(error_type,
- "Return value of %s%s%s() must %s%s, %s%s returned",
+ if (zf->common.type == ZEND_USER_FUNCTION) {
+ zend_type_error("Return value of %s%s%s() must %s%s, %s%s returned in %s on line %d",
+ fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind,
+ zf->op_array.filename->val, EG(current_execute_data)->opline->lineno);
+ } else {
+ zend_type_error("Return value of %s%s%s() must %s%s, %s%s returned",
+ fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind);
+ }
+}
+
+ZEND_API void zend_verify_internal_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
+{
+ const char *fname = zf->common.function_name->val;
+ const char *fsep;
+ const char *fclass;
+
+ if (zf->common.scope) {
+ fsep = "::";
+ fclass = zf->common.scope->name->val;
+ } else {
+ fsep = "";
+ fclass = "";
+ }
+
+ zend_error(E_CORE_ERROR, "Return value of %s%s%s() must %s%s, %s%s returned",
fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind);
}
@@ -814,39 +888,36 @@ 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_internal_return_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), "");
- 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), "");
+ if (ret_info->class_name) {
+ need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info *)ret_info, &class_name, &ce);
+ zend_verify_internal_return_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) && (Z_TYPE_P(ret) != IS_NULL || !ret_info->allow_null)) {
+ zend_verify_internal_return_error(zf, "be callable", "", zend_zval_type_name(ret), "");
+ return 0;
+ }
+ } else if (ret_info->type_hint == _IS_BOOL &&
+ EXPECTED(Z_TYPE_P(ret) == IS_FALSE || Z_TYPE_P(ret) == IS_TRUE)) {
+ /* pass */
+ } else {
+ /* Use strict check to verify return value of internal function */
+ zend_verify_internal_return_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;
@@ -856,34 +927,31 @@ 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_EXCEPTION | E_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(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_EXCEPTION | E_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_EXCEPTION | E_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_EXCEPTION | E_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(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(zf, "be callable", "", zend_zval_type_name(ret), "");
+ }
+ } else if (ret_info->type_hint == _IS_BOOL &&
+ EXPECTED(Z_TYPE_P(ret) == IS_FALSE || Z_TYPE_P(ret) == IS_TRUE)) {
+ /* pass */
+ } else if (UNEXPECTED(!zend_verify_scalar_type_hint(ret_info->type_hint, ret, ZEND_RET_USES_STRICT_TYPES()))) {
+ zend_verify_return_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
}
}
}
@@ -894,21 +962,17 @@ static inline int zend_verify_missing_return_type(zend_function *zf)
char *need_msg;
zend_class_entry *ce;
- if (ret_info->class_name) {
- char *class_name;
+ if (ret_info->type_hint) {
+ 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_EXCEPTION | E_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_EXCEPTION | E_ERROR, zf, "be of the type array", "", "none", "");
+ need_msg = zend_verify_arg_class_kind(ret_info, &class_name, &ce);
+ zend_verify_return_error(zf, need_msg, class_name, "none", "");
+ return 0;
} else if (ret_info->type_hint == IS_CALLABLE) {
- zend_verify_return_error(E_EXCEPTION | E_ERROR, zf, "be callable", "", "none", "");
-#if ZEND_DEBUG
+ zend_verify_return_error(zf, "be callable", "", "none", "");
} else {
- zend_error(E_ERROR, "Unknown typehint");
-#endif
+ zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), "none", "");
}
return 0;
}