summaryrefslogtreecommitdiff
path: root/Zend/zend_compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_compile.c')
-rw-r--r--Zend/zend_compile.c85
1 files changed, 81 insertions, 4 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 707d2ac9da..83c2573d79 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -5787,9 +5787,12 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fall
zend_ast *var_ast = param_ast->child[1];
zend_ast *default_ast = param_ast->child[2];
zend_ast *attributes_ast = param_ast->child[3];
+ zend_ast *doc_comment_ast = param_ast->child[4];
zend_string *name = zval_make_interned_string(zend_ast_get_zval(var_ast));
zend_bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
zend_bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0;
+ uint32_t visibility =
+ param_ast->attr & (ZEND_ACC_PUBLIC|ZEND_ACC_PROTECTED|ZEND_ACC_PRIVATE);
znode var_node, default_node;
zend_uchar opcode;
@@ -5862,16 +5865,16 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fall
if (type_ast) {
uint32_t default_type = default_ast ? Z_TYPE(default_node.u.constant) : IS_UNDEF;
+ zend_bool force_nullable = default_type == IS_NULL && !visibility;
op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
- arg_info->type = zend_compile_typename(
- type_ast, default_type == IS_NULL, /* use_arena */ 0);
+ arg_info->type = zend_compile_typename(type_ast, force_nullable, /* use_arena */ 0);
if (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_VOID) {
zend_error_noreturn(E_COMPILE_ERROR, "void cannot be used as a parameter type");
}
- if (default_type > IS_NULL && default_type != IS_CONSTANT_AST
+ if (default_type != IS_UNDEF && default_type != IS_CONSTANT_AST && !force_nullable
&& !zend_is_valid_default_value(arg_info->type, &default_node.u.constant)) {
zend_string *type_str = zend_type_to_string(arg_info->type);
zend_error_noreturn(E_COMPILE_ERROR,
@@ -5891,11 +5894,62 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fall
zend_alloc_cache_slots(zend_type_get_num_classes(arg_info->type));
}
- ZEND_TYPE_FULL_MASK(arg_info->type) |= _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic);
+ uint32_t arg_info_flags = _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic)
+ | (visibility ? _ZEND_IS_PROMOTED_BIT : 0);
+ ZEND_TYPE_FULL_MASK(arg_info->type) |= arg_info_flags;
if (opcode == ZEND_RECV) {
opline->op2.num = type_ast ?
ZEND_TYPE_FULL_MASK(arg_info->type) : MAY_BE_ANY;
}
+
+ if (visibility) {
+ zend_op_array *op_array = CG(active_op_array);
+ zend_class_entry *scope = op_array->scope;
+ zend_bool is_ctor =
+ scope && zend_string_equals_literal_ci(op_array->function_name, "__construct");
+ if (!is_ctor) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Cannot declare promoted property outside a constructor");
+ }
+ if ((op_array->fn_flags & ZEND_ACC_ABSTRACT)
+ || (scope->ce_flags & ZEND_ACC_INTERFACE)) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Cannot declare promoted property in an abstract constructor");
+ }
+ if (is_variadic) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Cannot declare variadic promoted property");
+ }
+ if (zend_hash_exists(&scope->properties_info, name)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::$%s",
+ ZSTR_VAL(scope->name), ZSTR_VAL(name));
+ }
+ if (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_CALLABLE) {
+ zend_string *str = zend_type_to_string(arg_info->type);
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Property %s::$%s cannot have type %s",
+ ZSTR_VAL(scope->name), ZSTR_VAL(name), ZSTR_VAL(str));
+ }
+
+ /* Always use uninitialized as the default. */
+ zval default_value;
+ ZVAL_UNDEF(&default_value);
+
+ /* Recompile the type, as it has different memory management requirements. */
+ zend_type type = ZEND_TYPE_INIT_NONE(0);
+ if (type_ast) {
+ type = zend_compile_typename(type_ast, /* force_allow_null */ 0, /* use_arena */ 1);
+ }
+
+ zend_string *doc_comment =
+ doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
+ zend_property_info *prop = zend_declare_typed_property(
+ scope, name, &default_value, visibility | ZEND_ACC_PROMOTED, doc_comment, type);
+ if (attributes_ast) {
+ zend_compile_attributes(
+ &prop->attributes, attributes_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY);
+ }
+ }
}
/* These are assigned at the end to avoid uninitialized memory in case of an error */
@@ -5907,6 +5961,29 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fall
op_array->num_args--;
}
zend_set_function_arg_flags((zend_function*)op_array);
+
+ for (i = 0; i < list->children; i++) {
+ zend_ast *param_ast = list->child[i];
+ zend_bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
+ uint32_t visibility =
+ param_ast->attr & (ZEND_ACC_PUBLIC|ZEND_ACC_PROTECTED|ZEND_ACC_PRIVATE);
+ if (!visibility) {
+ continue;
+ }
+
+ /* Emit $this->prop = $prop for promoted properties. */
+ zend_string *name = zend_ast_get_str(param_ast->child[1]);
+ znode name_node, value_node;
+ name_node.op_type = IS_CONST;
+ ZVAL_STR_COPY(&name_node.u.constant, name);
+ value_node.op_type = IS_CV;
+ value_node.u.op.var = lookup_cv(name);
+
+ zend_op *opline = zend_emit_op(NULL,
+ is_ref ? ZEND_ASSIGN_OBJ_REF : ZEND_ASSIGN_OBJ, NULL, &name_node);
+ opline->extended_value = zend_alloc_cache_slots(3);
+ zend_emit_op_data(&value_node);
+ }
}
/* }}} */