From 53e094ee9cf532a055cc3c57ffa97ceac678387f Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Wed, 17 Aug 2022 23:11:54 +0100 Subject: [PATCH 1/7] #2374 - Implement nullable object return type --- Library/ArgInfoDefinition.php | 37 ++++++++++++++++++++++----- Library/ClassMethod.php | 10 ++++++++ stub/types/obj.zep | 15 +++++++++++ tests/Extension/Types/ObjTypeTest.php | 28 ++++++++++++++++++++ 4 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 stub/types/obj.zep create mode 100644 tests/Extension/Types/ObjTypeTest.php diff --git a/Library/ArgInfoDefinition.php b/Library/ArgInfoDefinition.php index 489bf8b59..79eb42ab6 100644 --- a/Library/ArgInfoDefinition.php +++ b/Library/ArgInfoDefinition.php @@ -167,13 +167,9 @@ public function render(): void private function richRenderStart(): void { - if (array_key_exists('object', $this->functionLike->getReturnTypes())) { - $class = 'NULL'; - - if (1 === count($this->functionLike->getReturnClassTypes())) { - $class = key($this->functionLike->getReturnClassTypes()); - $class = escape_class($this->compilationContext->getFullName($class)); - } + if (array_key_exists('object', $this->functionLike->getReturnTypes()) && 1 === count($this->functionLike->getReturnClassTypes())) { + $class = key($this->functionLike->getReturnClassTypes()); + $class = escape_class($this->compilationContext->getFullName($class)); $this->codePrinter->output( sprintf( @@ -237,6 +233,33 @@ private function richRenderStart(): void return; } + if ($this->functionLike->isReturnTypeNullableObject()) { + $this->codePrinter->output('#if PHP_VERSION_ID >= 80000'); + $this->codePrinter->output( + sprintf( + 'ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(%s, %d, %d, %s)', + $this->name, + (int) $this->returnByRef, + $this->functionLike->getNumberOfRequiredParameters(), + 'MAY_BE_NULL|MAY_BE_OBJECT', + ) + ); + $this->codePrinter->output('#else'); + $this->codePrinter->output( + sprintf( + 'ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(%s, %d, %d, %s, %d)', + $this->name, + (int) $this->returnByRef, + $this->functionLike->getNumberOfRequiredParameters(), + 'IS_OBJECT', + 1, + ) + ); + $this->codePrinter->output('#endif'); + + return; + } + if (count($this->functionLike->getReturnTypes()) > 1) { $types = []; $mayBeTypes = $this->functionLike->getMayBeArgTypes(); diff --git a/Library/ClassMethod.php b/Library/ClassMethod.php index 8c1ec4748..7802cf7ce 100644 --- a/Library/ClassMethod.php +++ b/Library/ClassMethod.php @@ -2340,6 +2340,16 @@ public function isReturnTypesHintDetermined(): bool return true; } + /** + * Checks if method's return type is nullable object `?object`. + * + * @return bool + */ + public function isReturnTypeNullableObject(): bool + { + return count($this->returnTypes) === 2 && isset($this->returnTypes['object']) && isset($this->returnTypes['null']); + } + /** * Checks if the method have compatible return types. * diff --git a/stub/types/obj.zep b/stub/types/obj.zep new file mode 100644 index 000000000..65134b3ee --- /dev/null +++ b/stub/types/obj.zep @@ -0,0 +1,15 @@ + +namespace Stub\Types; + +class Obj +{ + public function nullableObjectReturnNull() -> object | null + { + return null; + } + + public function nullableObjectReturnObj() -> object | null + { + return new \stdClass(); + } +} diff --git a/tests/Extension/Types/ObjTypeTest.php b/tests/Extension/Types/ObjTypeTest.php new file mode 100644 index 000000000..d645480b8 --- /dev/null +++ b/tests/Extension/Types/ObjTypeTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Extension\Types; + +use PHPUnit\Framework\TestCase; +use Stub\Types\Obj; + +final class ObjTypeTest extends TestCase +{ + public function testIntFalse(): void + { + $class = new Obj(); + + $this->assertNull($class->nullableObjectReturnNull()); + $this->assertSame(new \stdClass(), $class->nullableObjectReturnObj()); + } +} From b450ec5466928efb70206633f4fffbc8212e10bf Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Wed, 17 Aug 2022 23:12:21 +0100 Subject: [PATCH 2/7] #2374 - Add ext/ files --- ext/config.m4 | 1 + ext/config.w32 | 2 +- ext/stub.c | 2 ++ ext/stub.h | 1 + ext/stub/types/obj.zep.c | 43 ++++++++++++++++++++++++++++++++++++++++ ext/stub/types/obj.zep.h | 27 +++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 ext/stub/types/obj.zep.c create mode 100644 ext/stub/types/obj.zep.h diff --git a/ext/config.m4 b/ext/config.m4 index f654c649f..c1fb9625c 100644 --- a/ext/config.m4 +++ b/ext/config.m4 @@ -215,6 +215,7 @@ if test "$PHP_STUB" = "yes"; then stub/typeoff.zep.c stub/types/maybe.zep.c stub/types/mixedtype.zep.c + stub/types/obj.zep.c stub/unknownclass.zep.c stub/unsettest.zep.c stub/usetest.zep.c diff --git a/ext/config.w32 b/ext/config.w32 index cea2bd118..505cec607 100644 --- a/ext/config.w32 +++ b/ext/config.w32 @@ -38,7 +38,7 @@ if (PHP_STUB != "no") { ADD_SOURCES(configure_module_dirname + "/stub/requires", "external3.zep.c", "stub"); ADD_SOURCES(configure_module_dirname + "/stub/router", "exception.zep.c route.zep.c", "stub"); ADD_SOURCES(configure_module_dirname + "/stub/typehinting", "testabstract.zep.c", "stub"); - ADD_SOURCES(configure_module_dirname + "/stub/types", "maybe.zep.c mixedtype.zep.c", "stub"); + ADD_SOURCES(configure_module_dirname + "/stub/types", "maybe.zep.c mixedtype.zep.c obj.zep.c", "stub"); ADD_FLAG("CFLAGS_STUB", "/D ZEPHIR_RELEASE /Oi /Ot /Oy /Ob2 /Gs /GF /Gy /GL"); ADD_FLAG("CFLAGS", "/D ZEPHIR_RELEASE /Oi /Ot /Oy /Ob2 /Gs /GF /Gy /GL"); ADD_FLAG("LDFLAGS", "/LTCG"); diff --git a/ext/stub.c b/ext/stub.c index aa6294f0a..23752125f 100644 --- a/ext/stub.c +++ b/ext/stub.c @@ -243,6 +243,7 @@ zend_class_entry *stub_typeinstances_ce; zend_class_entry *stub_typeoff_ce; zend_class_entry *stub_types_maybe_ce; zend_class_entry *stub_types_mixedtype_ce; +zend_class_entry *stub_types_obj_ce; zend_class_entry *stub_unknownclass_ce; zend_class_entry *stub_unsettest_ce; zend_class_entry *stub_usetest_ce; @@ -473,6 +474,7 @@ static PHP_MINIT_FUNCTION(stub) ZEPHIR_INIT(Stub_Typeoff); ZEPHIR_INIT(Stub_Types_MayBe); ZEPHIR_INIT(Stub_Types_MixedType); + ZEPHIR_INIT(Stub_Types_Obj); ZEPHIR_INIT(Stub_UnknownClass); ZEPHIR_INIT(Stub_Unsettest); ZEPHIR_INIT(Stub_UseTest); diff --git a/ext/stub.h b/ext/stub.h index 942bbaba8..48be14ef4 100644 --- a/ext/stub.h +++ b/ext/stub.h @@ -210,6 +210,7 @@ #include "stub/typeoff.zep.h" #include "stub/types/maybe.zep.h" #include "stub/types/mixedtype.zep.h" +#include "stub/types/obj.zep.h" #include "stub/unknownclass.zep.h" #include "stub/unsettest.zep.h" #include "stub/usetest.zep.h" diff --git a/ext/stub/types/obj.zep.c b/ext/stub/types/obj.zep.c new file mode 100644 index 000000000..d2b119f0c --- /dev/null +++ b/ext/stub/types/obj.zep.c @@ -0,0 +1,43 @@ + +#ifdef HAVE_CONFIG_H +#include "../../ext_config.h" +#endif + +#include +#include "../../php_ext.h" +#include "../../ext.h" + +#include +#include +#include + +#include "kernel/main.h" +#include "kernel/object.h" + + +ZEPHIR_INIT_CLASS(Stub_Types_Obj) +{ + ZEPHIR_REGISTER_CLASS(Stub\\Types, Obj, stub, types_obj, stub_types_obj_method_entry, 0); + + return SUCCESS; +} + +PHP_METHOD(Stub_Types_Obj, nullableObjectReturnNull) +{ + zval *this_ptr = getThis(); + + + + RETURN_NULL(); +} + +PHP_METHOD(Stub_Types_Obj, nullableObjectReturnObj) +{ + zval *this_ptr = getThis(); + + + + object_init(return_value); + return; +} + diff --git a/ext/stub/types/obj.zep.h b/ext/stub/types/obj.zep.h new file mode 100644 index 000000000..6854113fa --- /dev/null +++ b/ext/stub/types/obj.zep.h @@ -0,0 +1,27 @@ + +extern zend_class_entry *stub_types_obj_ce; + +ZEPHIR_INIT_CLASS(Stub_Types_Obj); + +PHP_METHOD(Stub_Types_Obj, nullableObjectReturnNull); +PHP_METHOD(Stub_Types_Obj, nullableObjectReturnObj); + +#if PHP_VERSION_ID >= 80000 +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_stub_types_obj_nullableobjectreturnnull, 0, 0, MAY_BE_NULL|MAY_BE_OBJECT) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stub_types_obj_nullableobjectreturnnull, 0, 0, IS_OBJECT, 1) +#endif +ZEND_END_ARG_INFO() + +#if PHP_VERSION_ID >= 80000 +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_stub_types_obj_nullableobjectreturnobj, 0, 0, MAY_BE_NULL|MAY_BE_OBJECT) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stub_types_obj_nullableobjectreturnobj, 0, 0, IS_OBJECT, 1) +#endif +ZEND_END_ARG_INFO() + +ZEPHIR_INIT_FUNCS(stub_types_obj_method_entry) { + PHP_ME(Stub_Types_Obj, nullableObjectReturnNull, arginfo_stub_types_obj_nullableobjectreturnnull, ZEND_ACC_PUBLIC) + PHP_ME(Stub_Types_Obj, nullableObjectReturnObj, arginfo_stub_types_obj_nullableobjectreturnobj, ZEND_ACC_PUBLIC) + PHP_FE_END +}; From 5ef3977f83fbc087ffbf0c5501cad21a64965292 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Wed, 17 Aug 2022 23:12:47 +0100 Subject: [PATCH 3/7] #2374 - Force `string` to `int` --- Library/Expression/NativeArray.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Expression/NativeArray.php b/Library/Expression/NativeArray.php index 2b73152b6..ecec1dc04 100644 --- a/Library/Expression/NativeArray.php +++ b/Library/Expression/NativeArray.php @@ -221,7 +221,7 @@ public function compile(array $expression, CompilationContext $compilationContex */ $arrayLength = count($expression['left']); if ($arrayLength >= 33 && function_exists('gmp_nextprime')) { - $arrayLength = gmp_strval(gmp_nextprime($arrayLength - 1)); + $arrayLength = (int)gmp_strval(gmp_nextprime($arrayLength - 1)); } if ($this->expectingVariable && $symbolVariable->getVariantInits() >= 1) { From 66413daa3e3a7148fa933c6f712006ca3653c118 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Wed, 17 Aug 2022 23:14:52 +0100 Subject: [PATCH 4/7] #2374 - Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d43b4c719..43d8674ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format based on [Keep a Changelog](https://keepachangelog.com) and this project adheres to [Semantic Versioning](https://semver.org). ## [Unreleased] +### Fixed +- Fixed generation of `ARG_INFO` for nullable object (`?object`) [#2374](https://github.com/zephir-lang/zephir/issues/2374) ## [0.16.0] - 2022-03-20 ### Added From 373b23f159bbfd83678470712d436bb66a82a3b6 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Wed, 17 Aug 2022 23:15:46 +0100 Subject: [PATCH 5/7] #2374 - Make condition strict --- Library/ArgInfoDefinition.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/ArgInfoDefinition.php b/Library/ArgInfoDefinition.php index 79eb42ab6..8e55bc213 100644 --- a/Library/ArgInfoDefinition.php +++ b/Library/ArgInfoDefinition.php @@ -469,7 +469,7 @@ private function allowNull(array $parameter): bool return false; } - if ('null' == $parameter['default']['type']) { + if ('null' === $parameter['default']['type']) { return true; } From 36755d18475c493eba359d7e471d9cade1b2e94f Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Wed, 17 Aug 2022 23:16:52 +0100 Subject: [PATCH 6/7] #2374 - Fix CS --- Library/Expression/NativeArray.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Expression/NativeArray.php b/Library/Expression/NativeArray.php index ecec1dc04..72c87e03f 100644 --- a/Library/Expression/NativeArray.php +++ b/Library/Expression/NativeArray.php @@ -221,7 +221,7 @@ public function compile(array $expression, CompilationContext $compilationContex */ $arrayLength = count($expression['left']); if ($arrayLength >= 33 && function_exists('gmp_nextprime')) { - $arrayLength = (int)gmp_strval(gmp_nextprime($arrayLength - 1)); + $arrayLength = (int) gmp_strval(gmp_nextprime($arrayLength - 1)); } if ($this->expectingVariable && $symbolVariable->getVariantInits() >= 1) { From 98e103c3ef3dcd248d83661c6570caa428fcbf4d Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Wed, 17 Aug 2022 23:18:10 +0100 Subject: [PATCH 7/7] #2374 - Change assert method --- tests/Extension/Types/ObjTypeTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Extension/Types/ObjTypeTest.php b/tests/Extension/Types/ObjTypeTest.php index d645480b8..0cab73519 100644 --- a/tests/Extension/Types/ObjTypeTest.php +++ b/tests/Extension/Types/ObjTypeTest.php @@ -14,6 +14,7 @@ namespace Extension\Types; use PHPUnit\Framework\TestCase; +use stdClass; use Stub\Types\Obj; final class ObjTypeTest extends TestCase @@ -23,6 +24,6 @@ public function testIntFalse(): void $class = new Obj(); $this->assertNull($class->nullableObjectReturnNull()); - $this->assertSame(new \stdClass(), $class->nullableObjectReturnObj()); + $this->assertInstanceOf(stdClass::class, $class->nullableObjectReturnObj()); } }