diff --git a/Zend/tests/typehints/mixed.phpt b/Zend/tests/typehints/mixed.phpt new file mode 100644 index 0000000000000..dac5f91b65ed0 --- /dev/null +++ b/Zend/tests/typehints/mixed.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test various types passed to mixed type. +--FILE-- +test(123)); +--EXPECT-- +int(123) diff --git a/Zend/tests/typehints/mixed_nullable_parameter.phpt b/Zend/tests/typehints/mixed_nullable_parameter.phpt new file mode 100644 index 0000000000000..922f394fb53e0 --- /dev/null +++ b/Zend/tests/typehints/mixed_nullable_parameter.phpt @@ -0,0 +1,10 @@ +--TEST-- +Test nullable mixed parameter type. +--FILE-- +type) == IS_MIXED && ZEND_TYPE_ALLOW_NULL(arg_infos->type)) { + zend_error_noreturn(E_COMPILE_ERROR, "Mixed type cannot be nullable"); + } + arg_infos++; op_array->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE; } else { @@ -5581,6 +5587,10 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ zend_error_noreturn(E_COMPILE_ERROR, "void cannot be used as a parameter type"); } + if (ZEND_TYPE_CODE(arg_info->type) == IS_MIXED && ZEND_TYPE_ALLOW_NULL(arg_info->type)) { + zend_error_noreturn(E_COMPILE_ERROR, "Mixed type cannot be nullable"); + } + if (type_ast->kind == ZEND_AST_TYPE) { if (ZEND_TYPE_CODE(arg_info->type) == IS_ARRAY) { if (default_ast && !has_null_default diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 55c24f31e98b4..60004fba5b79d 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -945,6 +945,8 @@ static zend_always_inline zend_bool zend_check_type( } else if (ZEND_TYPE_CODE(type) == _IS_BOOL && EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) { return 1; + } else if (ZEND_TYPE_CODE(type) == IS_MIXED) { + return 1; } else { return zend_verify_scalar_type_hint(ZEND_TYPE_CODE(type), arg, is_return_type ? ZEND_RET_USES_STRICT_TYPES() : ZEND_ARG_USES_STRICT_TYPES()); diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index be605a49de6c2..cc7f3c8c2c0ec 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -253,7 +253,10 @@ static int zend_do_perform_arg_type_hint_check(const zend_function *fe, zend_arg } if (!ZEND_TYPE_IS_SET(proto_arg_info->type)) { - /* Child defines a type, but parent doesn't, violates LSP */ + /* Child defines a type, but parent doesn't, violates LSP, unless it's a mixed type */ + if (ZEND_TYPE_CODE(fe_arg_info->type) == IS_MIXED) { + return 1; + } return 0; } @@ -359,6 +362,9 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c if (proto->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { /* Removing a return type is not valid. */ if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) { + if (ZEND_TYPE_CODE(proto->common.arg_info[-1].type) == IS_MIXED) { + return 1; + } return 0; } diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 59b0af1a4a818..2cb8eadc19569 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -407,6 +407,7 @@ struct _zend_ast_ref { #define IS_ITERABLE 18 #define IS_VOID 19 #define _IS_NUMBER 20 +#define IS_MIXED 21 static zend_always_inline zend_uchar zval_get_type(const zval* pz) { return pz->u1.v.type;