From ff76511a08088a6d40af0a1479c222d2756fe054 Mon Sep 17 00:00:00 2001 From: Zeev Suraski Date: Thu, 6 Mar 2003 14:31:17 +0000 Subject: [PATCH] Add class type hints --- Zend/zend_compile.c | 15 ++++++++++++++- Zend/zend_compile.h | 3 ++- Zend/zend_execute.c | 33 ++++++++++++++++++++++++++++----- Zend/zend_language_parser.y | 26 ++++++++++++++++---------- 4 files changed, 60 insertions(+), 17 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 644f8561f6..fb6d394abf 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1085,7 +1085,7 @@ void zend_do_end_function_declaration(znode *function_token TSRMLS_DC) } -void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, zend_uchar pass_type TSRMLS_DC) +void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, zend_uchar pass_type TSRMLS_DC) { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); @@ -1113,6 +1113,19 @@ void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initia CG(active_op_array)->arg_types[0]=(unsigned char) offset->u.constant.value.lval; CG(active_op_array)->arg_types[offset->u.constant.value.lval] = pass_type; } + + if (class_type->op_type != IS_UNUSED) { + znode passed_var = opline->result; + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + + opline->opcode = ZEND_VERIFY_CE; + opline->op1 = *class_type; + opline->op2 = passed_var; + opline->extended_value = offset->u.constant.value.lval; + } else { + opline->result.u.EA.type |= EXT_TYPE_UNUSED; + } } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index f24e14b8c8..414736b8f0 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -311,7 +311,7 @@ void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC); int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier); void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC); void zend_do_end_function_declaration(znode *function_token TSRMLS_DC); -void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, zend_uchar pass_type TSRMLS_DC); +void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, zend_uchar pass_type TSRMLS_DC); int zend_do_begin_function_call(znode *function_name TSRMLS_DC); void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC); void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC); @@ -662,6 +662,7 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_START_NAMESPACE 143 #define ZEND_ADD_INTERFACE 144 +#define ZEND_VERIFY_CE 145 /* end of block */ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 412e04380b..11203f68ae 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2966,9 +2966,9 @@ int zend_recv_handler(ZEND_OPCODE_HANDLER_ARGS) PZVAL_UNLOCK(*EX_T(EX(opline)->result.u.var).var.ptr_ptr); } } else if (PZVAL_IS_REF(*param)) { - zend_assign_to_variable_reference(NULL, get_zval_ptr_ptr(&EX(opline)->result, EX(Ts), BP_VAR_W), param, NULL TSRMLS_CC); + zend_assign_to_variable_reference(&EX(opline)->result, get_zval_ptr_ptr(&EX(opline)->result, EX(Ts), BP_VAR_W), param, NULL TSRMLS_CC); } else { - zend_assign_to_variable(NULL, &EX(opline)->result, NULL, *param, IS_VAR, EX(Ts) TSRMLS_CC); + zend_assign_to_variable(&EX(opline)->result, &EX(opline)->result, NULL, *param, IS_VAR, EX(Ts) TSRMLS_CC); } NEXT_OPCODE(); @@ -2998,13 +2998,13 @@ int zend_recv_init_handler(ZEND_OPCODE_HANDLER_ARGS) param = NULL; assignment_value = &EX(opline)->op2.u.constant; } - zend_assign_to_variable(NULL, &EX(opline)->result, NULL, assignment_value, IS_VAR, EX(Ts) TSRMLS_CC); + zend_assign_to_variable(&EX(opline)->result, &EX(opline)->result, NULL, assignment_value, IS_VAR, EX(Ts) TSRMLS_CC); } else { assignment_value = *param; if (PZVAL_IS_REF(assignment_value)) { - zend_assign_to_variable_reference(NULL, get_zval_ptr_ptr(&EX(opline)->result, EX(Ts), BP_VAR_W), param, NULL TSRMLS_CC); + zend_assign_to_variable_reference(&EX(opline)->result, get_zval_ptr_ptr(&EX(opline)->result, EX(Ts), BP_VAR_W), param, NULL TSRMLS_CC); } else { - zend_assign_to_variable(NULL, &EX(opline)->result, NULL, assignment_value, IS_VAR, EX(Ts) TSRMLS_CC); + zend_assign_to_variable(&EX(opline)->result, &EX(opline)->result, NULL, assignment_value, IS_VAR, EX(Ts) TSRMLS_CC); } } @@ -3993,6 +3993,28 @@ int zend_add_interface_handler(ZEND_OPCODE_HANDLER_ARGS) NEXT_OPCODE(); } + +int zend_verify_ce_handler(ZEND_OPCODE_HANDLER_ARGS) +{ + zval *arg = get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2), BP_VAR_R); + zend_class_entry *ce = EX_T(EX(opline)->op1.u.var).EA.class_entry; + + if ((Z_TYPE_P(arg) != IS_OBJECT) + || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) { + char *error_msg; + + if (ce->ce_flags & ZEND_ACC_INTERFACE) { + error_msg = "implement interface"; + } else { + error_msg = "be an instance of"; + } + zend_error(E_ERROR, "Argument %d must %s %s", EX(opline)->extended_value, error_msg, ce->name); + } + + NEXT_OPCODE(); +} + + void zend_init_opcodes_handlers() { zend_opcode_handlers[ZEND_NOP] = zend_nop_handler; @@ -4170,6 +4192,7 @@ void zend_init_opcodes_handlers() zend_opcode_handlers[ZEND_START_NAMESPACE] = zend_start_namespace_handler; zend_opcode_handlers[ZEND_ADD_INTERFACE] = zend_add_interface_handler; + zend_opcode_handlers[ZEND_VERIFY_CE] = zend_verify_ce_handler; } /* diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 50d495fbd6..c25ce39f08 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -438,19 +438,25 @@ parameter_list: non_empty_parameter_list: - T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$1, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_NONE TSRMLS_CC); } - | '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_FORCE TSRMLS_CC); } - | '&' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$4, BYREF_FORCE TSRMLS_CC); } - | T_CONST T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_NONE TSRMLS_CC); } - | T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$1, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$3, BYREF_NONE TSRMLS_CC); } - | non_empty_parameter_list ',' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_NONE TSRMLS_CC); } - | non_empty_parameter_list ',' '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_FORCE TSRMLS_CC); } - | non_empty_parameter_list ',' '&' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$6, BYREF_FORCE TSRMLS_CC); } - | non_empty_parameter_list ',' T_CONST T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, BYREF_NONE TSRMLS_CC); } - | non_empty_parameter_list ',' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$5, BYREF_NONE TSRMLS_CC); } + optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$1, BYREF_NONE TSRMLS_CC); } + | optional_class_type '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$1, BYREF_FORCE TSRMLS_CC); } + | optional_class_type '&' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$5, &$1, BYREF_FORCE TSRMLS_CC); } + | T_CONST optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$2, BYREF_NONE TSRMLS_CC); } + | optional_class_type T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$4, &$1, BYREF_NONE TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$3, BYREF_NONE TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$3, BYREF_FORCE TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$7, &$3, BYREF_FORCE TSRMLS_CC); } + | non_empty_parameter_list ',' T_CONST optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$4, BYREF_NONE TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$6, &$3, BYREF_NONE TSRMLS_CC); } ; +optional_class_type: + /* empty */ { $$.op_type = IS_UNUSED; } + | namespace_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); } + | T_STRING { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); } +; + function_call_parameter_list: non_empty_function_call_parameter_list { $$ = $1; } | /* empty */ { $$.u.constant.value.lval = 0; } -- 2.50.1