diff --git a/Zend/Optimizer/dfa_pass.c b/Zend/Optimizer/dfa_pass.c index 77dc322fbdec..ca80ff1624c5 100644 --- a/Zend/Optimizer/dfa_pass.c +++ b/Zend/Optimizer/dfa_pass.c @@ -252,15 +252,68 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op free_alloca(shiftlist, use_heap); } -static bool safe_instanceof(const zend_class_entry *ce1, const zend_class_entry *ce2) { - if (ce1 == ce2) { +/* Returns true if every instance of ce1 (or a subclass) is provably an instance + * of the target class. target_ce is the resolved class entry for the target + * when available; it may be NULL for a class declared in the same compilation + * unit that is not yet linked, in which case we fall back to matching + * target_lc against ce1's own declared parent and interfaces. */ +static bool safe_instanceof( + const zend_class_entry *ce1, + const zend_class_entry *target_ce, + const zend_string *target_lc, + const zend_script *script, + const zend_op_array *op_array +) { + if (target_ce && ce1 == target_ce) { return true; } - if (!(ce1->ce_flags & ZEND_ACC_LINKED)) { - /* This case could be generalized, similarly to unlinked_instanceof */ - return false; + if (zend_string_equals_ci(ce1->name, target_lc)) { + return true; + } + if (ce1->ce_flags & ZEND_ACC_LINKED) { + return target_ce && instanceof_function(ce1, target_ce); } - return instanceof_function(ce1, ce2); + + for (uint32_t i = 0; i < ce1->num_interfaces; i++) { + const zend_class_entry *iface; + if (ce1->ce_flags & ZEND_ACC_RESOLVED_INTERFACES) { + /* Unlike the normal instanceof_function(), we have to perform a recursive + * check here, as the parent interfaces might not have been fully copied yet. */ + iface = ce1->interfaces[i]; + } else { + if (zend_string_equals_ci(ce1->interface_names[i].lc_name, target_lc)) { + return true; + } + + iface = zend_optimizer_get_class_entry(script, op_array, ce1->interface_names[i].lc_name); + } + + /* Skip if unresolvable/not-yet-copied, or the class implements itself. */ + if (!iface || iface == ce1) { + continue; + } + + if (safe_instanceof(iface, target_ce, target_lc, script, op_array)) { + return true; + } + } + + /* ce1 is unlinked here (the linked case returned above), so the + * parent/parent_name union holds the as-yet-unresolved parent name. */ + if (ce1->parent_name) { + if (zend_string_equals_ci(ce1->parent_name, target_lc)) { + return true; + } + + zend_string *parent_lc = zend_string_tolower(ce1->parent_name); + const zend_class_entry *parent = zend_optimizer_get_class_entry(script, op_array, parent_lc); + zend_string_release(parent_lc); + if (parent && parent != ce1 && safe_instanceof(parent, target_ce, target_lc, script, op_array)) { + return true; + } + } + + return false; } static inline bool can_elide_list_type( @@ -279,8 +332,8 @@ static inline bool can_elide_list_type( if (ZEND_TYPE_HAS_NAME(*single_type)) { zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(*single_type)); const zend_class_entry *ce = zend_optimizer_get_class_entry(script, op_array, lcname); + bool result = use_info->ce && safe_instanceof(use_info->ce, ce, lcname, script, op_array); zend_string_release(lcname); - bool result = ce && safe_instanceof(use_info->ce, ce); if (result == !is_intersection) { return result; } @@ -289,6 +342,16 @@ static inline bool can_elide_list_type( return is_intersection; } +/* Whether the SSA variable is the result of a ZEND_FETCH_THIS, i.e. is $this. */ +static bool zend_ssa_var_is_this(const zend_op_array *op_array, const zend_ssa *ssa, int var) { + if (var < 0) { + return false; + } + + int def = ssa->vars[var].definition; + return def >= 0 && op_array->opcodes[def].opcode == ZEND_FETCH_THIS; +} + static inline bool can_elide_return_type_check( const zend_script *script, zend_op_array *op_array, zend_ssa *ssa, zend_ssa_op *ssa_op) { zend_arg_info *arg_info = &op_array->arg_info[-1]; @@ -309,6 +372,16 @@ static inline bool can_elide_return_type_check( return true; } + /* A `static` return type only accepts the late-static-bound class. Returning + * $this always satisfies it, since $this is by definition an instance of + * `static`. Closures are excluded as they may be rebound to another scope. */ + if (disallowed_types == MAY_BE_OBJECT + && (ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_STATIC) + && !(op_array->fn_flags & ZEND_ACC_CLOSURE) + && zend_ssa_var_is_this(op_array, ssa, ssa_op->op1_use)) { + return true; + } + if (disallowed_types == MAY_BE_OBJECT && use_info->ce && ZEND_TYPE_IS_COMPLEX(arg_info->type)) { return can_elide_list_type(script, op_array, use_info, arg_info->type); } diff --git a/Zend/tests/return_types/025_2.phpt b/Zend/tests/return_types/025_2.phpt new file mode 100644 index 000000000000..50683c5c1267 --- /dev/null +++ b/Zend/tests/return_types/025_2.phpt @@ -0,0 +1,14 @@ +--TEST-- +Return type of self is allowed in closure but $this return value must be checked as closure might not be bound to a class +--FILE-- +getMessage(), PHP_EOL; +} +?> +--EXPECT-- +Error: Using $this when not in object context diff --git a/ext/opcache/tests/opt/verify_return_type/direct_extended_interface_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/direct_extended_interface_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..d7ccf3e9df66 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/direct_extended_interface_verify_return_type_for_this_class.phpt @@ -0,0 +1,59 @@ +--TEST-- +Return type check elision for direct interface return type and $this in class method when interface extends another one +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=3, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-13 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("i2") +0001 DECLARE_CLASS string("c") +0002 RETURN int(1) + +C::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:7-9 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=3, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-13 +0000 DECLARE_CLASS string("i2") +0001 DECLARE_CLASS string("c") +0002 RETURN int(1) + +C::foo: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:7-9 +0000 T0 = FETCH_THIS +0001 RETURN T0 diff --git a/ext/opcache/tests/opt/verify_return_type/direct_interface_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/direct_interface_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..46737c9fc310 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/direct_interface_verify_return_type_for_this_class.phpt @@ -0,0 +1,56 @@ +--TEST-- +Return type check elision for direct interface return type and $this in class method +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=2, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-12 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("c") +0001 RETURN int(1) + +C::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:6-8 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=2, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-12 +0000 DECLARE_CLASS string("c") +0001 RETURN int(1) + +C::foo: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:6-8 +0000 T0 = FETCH_THIS +0001 RETURN T0 diff --git a/ext/opcache/tests/opt/verify_return_type/inherited_interface_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/inherited_interface_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..f585af5919cc --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/inherited_interface_verify_return_type_for_this_class.phpt @@ -0,0 +1,61 @@ +--TEST-- +Return type check elision for inherited interface return type and $this in class method +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=3, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-12 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("i2") +0001 DECLARE_CLASS string("c") +0002 RETURN int(1) + +C::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:6-8 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=3, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-12 +0000 DECLARE_CLASS string("i2") +0001 DECLARE_CLASS string("c") +0002 RETURN int(1) + +C::foo: + ; (lines=3, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:6-8 +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) diff --git a/ext/opcache/tests/opt/verify_return_type/inherited_interface_via_class_inheritance_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/inherited_interface_via_class_inheritance_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..49c0b922f47b --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/inherited_interface_via_class_inheritance_verify_return_type_for_this_class.phpt @@ -0,0 +1,65 @@ +--TEST-- +Return type check elision for inherited interface via class extension return type and $this in class method +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=4, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-14 + ; return [] RANGE[0..0] +0000 DECLARE_CLASS string("i2") +0001 DECLARE_CLASS string("c1") +0002 DECLARE_CLASS_DELAYED string("c2") string("c1") +0003 RETURN int(1) + +C2::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:8-10 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=4, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-14 +0000 DECLARE_CLASS string("i2") +0001 DECLARE_CLASS string("c1") +0002 DECLARE_CLASS_DELAYED string("c2") string("c1") +0003 RETURN int(1) + +C2::foo: + ; (lines=3, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:8-10 +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) diff --git a/ext/opcache/tests/opt/verify_return_type/optimizer_inherited_interface_via_interface_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/optimizer_inherited_interface_via_interface_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..c3bf3db18186 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/optimizer_inherited_interface_via_interface_verify_return_type_for_this_class.phpt @@ -0,0 +1,81 @@ +--TEST-- +Return type check elision in the optimizer for an interface reached through a (resolvable) implemented interface and $this +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=3, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-13 + ; return [] RANGE[0..0] +0000 JMPZ bool(true) 0002 +0001 DECLARE_CLASS string("d") +0002 RETURN int(1) + +D::getIterator: + ; (lines=5, args=0, vars=0, tmps=2) + ; (before optimizer) + ; %s:4-6 + ; return [] RANGE[0..0] +0000 T0 = NEW 0 string("Exception") +0001 DO_FCALL +0002 THROW T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (new) + +D::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:7-9 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=2, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-13 +0000 DECLARE_CLASS string("d") +0001 RETURN int(1) + +D::getIterator: + ; (lines=3, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:4-6 +0000 T0 = NEW 0 string("Exception") +0001 DO_FCALL +0002 THROW T0 +LIVE RANGES: + 0: 0001 - 0002 (new) + +D::foo: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:7-9 +0000 T0 = FETCH_THIS +0001 RETURN T0 diff --git a/ext/opcache/tests/opt/verify_return_type/optimizer_inherited_interface_via_parent_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/optimizer_inherited_interface_via_parent_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..5476bf9435e7 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/optimizer_inherited_interface_via_parent_verify_return_type_for_this_class.phpt @@ -0,0 +1,55 @@ +--TEST-- +Return type check elision in the optimizer for an interface reached through a (resolvable) parent class and $this +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=3, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-10 + ; return [] RANGE[0..0] +0000 JMPZ bool(true) 0002 +0001 DECLARE_CLASS string("c") string("arrayobject") +0002 RETURN int(1) + +C::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:4-6 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=2, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-10 +0000 DECLARE_CLASS string("c") string("arrayobject") +0001 RETURN int(1) + +C::foo: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:4-6 +0000 T0 = FETCH_THIS +0001 RETURN T0 diff --git a/ext/opcache/tests/opt/verify_return_type/parent_explicit_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/parent_explicit_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..83df0bde2de5 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/parent_explicit_verify_return_type_for_this_class.phpt @@ -0,0 +1,54 @@ +--TEST-- +Return type check elision for explicit parent return type and $this in class method +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-12 + ; return [] RANGE[0..0] +0000 RETURN int(1) + +C2::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:6-8 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-12 +0000 RETURN int(1) + +C2::foo: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:6-8 +0000 T0 = FETCH_THIS +0001 RETURN T0 diff --git a/ext/opcache/tests/opt/verify_return_type/parent_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/parent_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..e232df9b5803 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/parent_verify_return_type_for_this_class.phpt @@ -0,0 +1,54 @@ +--TEST-- +Return type check elision for parent return type and $this in class method +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-12 + ; return [] RANGE[0..0] +0000 RETURN int(1) + +C2::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:6-8 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-12 +0000 RETURN int(1) + +C2::foo: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:6-8 +0000 T0 = FETCH_THIS +0001 RETURN T0 diff --git a/ext/opcache/tests/opt/verify_return_type/self_explicit_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/self_explicit_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..289b8c66e0d1 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/self_explicit_verify_return_type_for_this_class.phpt @@ -0,0 +1,52 @@ +--TEST-- +Return type check elision for explicit self return type and $this in class method +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-10 + ; return [] RANGE[0..0] +0000 RETURN int(1) + +C::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:4-6 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-10 +0000 RETURN int(1) + +C::foo: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:4-6 +0000 T0 = FETCH_THIS +0001 RETURN T0 diff --git a/ext/opcache/tests/opt/verify_return_type/self_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/self_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..daddf47f3327 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/self_verify_return_type_for_this_class.phpt @@ -0,0 +1,52 @@ +--TEST-- +Return type check elision for self return type and $this in class method +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-10 + ; return [] RANGE[0..0] +0000 RETURN int(1) + +C::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:4-6 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-10 +0000 RETURN int(1) + +C::foo: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:4-6 +0000 T0 = FETCH_THIS +0001 RETURN T0 diff --git a/ext/opcache/tests/opt/verify_return_type/self_verify_return_type_for_this_trait.phpt b/ext/opcache/tests/opt/verify_return_type/self_verify_return_type_for_this_trait.phpt new file mode 100644 index 000000000000..db6974f66fe3 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/self_verify_return_type_for_this_trait.phpt @@ -0,0 +1,55 @@ +--TEST-- +Return type check elision for self return type and $this in trait method +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-10 + ; return [] RANGE[0..0] +0000 RETURN int(1) + +T::foo: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:4-6 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-10 +0000 RETURN int(1) + +T::foo: + ; (lines=3, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:4-6 +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) diff --git a/ext/opcache/tests/opt/verify_return_type/static_verify_return_type_for_this_class.phpt b/ext/opcache/tests/opt/verify_return_type/static_verify_return_type_for_this_class.phpt new file mode 100644 index 000000000000..7605c0b4e45f --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/static_verify_return_type_for_this_class.phpt @@ -0,0 +1,52 @@ +--TEST-- +Return type check elision for static return type and $this in class method +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-10 + ; return [] RANGE[0..0] +0000 RETURN int(1) + +C::returnStatic: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:4-6 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-10 +0000 RETURN int(1) + +C::returnStatic: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:4-6 +0000 T0 = FETCH_THIS +0001 RETURN T0 diff --git a/ext/opcache/tests/opt/verify_return_type/static_verify_return_type_for_this_trait.phpt b/ext/opcache/tests/opt/verify_return_type/static_verify_return_type_for_this_trait.phpt new file mode 100644 index 000000000000..b8bd13ab9316 --- /dev/null +++ b/ext/opcache/tests/opt/verify_return_type/static_verify_return_type_for_this_trait.phpt @@ -0,0 +1,52 @@ +--TEST-- +Return type check elision for static return type and $this in trait method +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x30000 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (before optimizer) + ; %s:1-10 + ; return [] RANGE[0..0] +0000 RETURN int(1) + +T::returnStatic: + ; (lines=5, args=0, vars=0, tmps=1) + ; (before optimizer) + ; %s:4-6 + ; return [] RANGE[0..0] +0000 T0 = FETCH_THIS +0001 VERIFY_RETURN_TYPE T0 +0002 RETURN T0 +0003 VERIFY_RETURN_TYPE +0004 RETURN null +LIVE RANGES: + 0: 0001 - 0002 (tmp/var) + +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s:1-10 +0000 RETURN int(1) + +T::returnStatic: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:4-6 +0000 T0 = FETCH_THIS +0001 RETURN T0