mirror of
https://github.com/php/php-src.git
synced 2026-04-12 18:43:37 +02:00
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.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
44
ext/opcache/tests/opt/verify_return_type.phpt
Normal file
44
ext/opcache/tests/opt/verify_return_type.phpt
Normal file
@@ -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--
|
||||
<?php require_once('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test1 {
|
||||
final public function getIntOrFloat(int $i): int|float {
|
||||
return $i;
|
||||
}
|
||||
final public function getInt(): int {
|
||||
return $this->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
|
||||
Reference in New Issue
Block a user