summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2021-03-18 17:11:56 +0100
committerNikita Popov <nikita.ppv@gmail.com>2021-03-18 17:11:56 +0100
commitdcac654fd56a2cecec0c187ba061ecc82bbc9031 (patch)
tree57fd146f6a4deb209c0ebae32341066cf0cd7836 /Zend
parent2f73cbb1b10f197674f4adb15f39a1d2d1aa4824 (diff)
downloadphp-git-dcac654fd56a2cecec0c187ba061ecc82bbc9031.tar.gz
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.
Diffstat (limited to 'Zend')
-rw-r--r--Zend/Optimizer/zend_inference.c13
1 files changed, 12 insertions, 1 deletions
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;
}