From dcac654fd56a2cecec0c187ba061ecc82bbc9031 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 18 Mar 2021 17:11:56 +0100 Subject: Allow inferring narrowed return type Even if an explicit return type is given, we might still infer a more narrow one based on return statements. We shouldn't pessimize this just because a type has been declared. --- Zend/Optimizer/zend_inference.c | 13 +++++++- ext/opcache/tests/opt/verify_return_type.phpt | 44 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/opt/verify_return_type.phpt diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index 42f37fa0c9..e5d476d01d 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -3519,6 +3519,12 @@ static zend_always_inline int _zend_update_type_info( } else { zend_arg_info *ret_info = op_array->arg_info - 1; tmp = zend_fetch_arg_info_type(script, ret_info, &ce); + + // TODO: We could model more precisely how illegal types are converted. + uint32_t extra_types = t1 & ~tmp; + if (!extra_types) { + tmp &= t1; + } } if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) { UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); @@ -4019,6 +4025,11 @@ void zend_func_return_info(const zend_op_array *op_array, return; } + if (!ret->type) { + /* We will intersect the type later. */ + ret->type = MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_KEY_ANY; + } + for (j = 0; j < blocks_count; j++) { if ((blocks[j].flags & ZEND_BB_REACHABLE) && blocks[j].len != 0) { zend_op *opline = op_array->opcodes + blocks[j].start + blocks[j].len - 1; @@ -4178,10 +4189,10 @@ void zend_func_return_info(const zend_op_array *op_array, if (tmp_has_range < 0) { tmp_has_range = 0; } - ret->type = tmp; ret->ce = tmp_ce; ret->is_instanceof = tmp_is_instanceof; } + ret->type &= tmp; ret->range = tmp_range; ret->has_range = tmp_has_range; } diff --git a/ext/opcache/tests/opt/verify_return_type.phpt b/ext/opcache/tests/opt/verify_return_type.phpt new file mode 100644 index 0000000000..c1384c7af8 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type.phpt @@ -0,0 +1,44 @@ +--TEST-- +Return type check elision +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x20000 +opcache.preload= +--SKIPIF-- + +--FILE-- +getIntOrFloat(); + } +} + +?> +--EXPECTF-- +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s +0000 RETURN int(1) + +Test1::getIntOrFloat: + ; (lines=2, args=1, vars=1, tmps=0) + ; (after optimizer) + ; %s +0000 CV0($i) = RECV 1 +0001 RETURN CV0($i) + +Test1::getInt: + ; (lines=3, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s +0000 INIT_METHOD_CALL 0 THIS string("getIntOrFloat") +0001 V0 = DO_UCALL +0002 RETURN V0 -- cgit v1.2.1