Skip to content

Commit

Permalink
Generate code for never return type
Browse files Browse the repository at this point in the history
  • Loading branch information
alekitto authored and nicolas-grekas committed May 3, 2022
1 parent 88dda72 commit 0232ad5
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public static function generate(string $returnedValueExpression, ?ReflectionMeth
return $returnedValueExpression . ";\nreturn;";
}

if ($originalReturnType instanceof ReflectionNamedType && $originalReturnType->getName() === 'never') {
return $returnedValueExpression . ';';
}

return 'return ' . $returnedValueExpression . ';';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
use ProxyManagerTestAsset\ClassWithPublicStringTypedProperty;
use ProxyManagerTestAsset\ClassWithSelfHint;
use ProxyManagerTestAsset\EmptyClass;
use ProxyManagerTestAsset\NeverCounter;
use ProxyManagerTestAsset\OtherObjectAccessClass;
use ProxyManagerTestAsset\VoidCounter;
use ReflectionClass;
use ReflectionProperty;
use RuntimeException;
use stdClass;

use function array_key_exists;
Expand Down Expand Up @@ -1547,7 +1549,46 @@ static function (
self::assertSame($initialCounter + $increment, $proxy->counter);
}

private static function isPropertyInitialized($object, ReflectionProperty $property): bool
/**
* @requires PHP 8.1
*
* @psalm-suppress UnusedVariable this method uses by-ref assignment of properties, and isn't recognized by static analysis
* @psalm-suppress UndefinedClass Class, interface or enum named never does not exist
*/
public function testWillExecuteLogicInANeverMethod(): void
{
$initialCounter = random_int(10, 1000);

$proxy = (new LazyLoadingGhostFactory())->createProxy(
NeverCounter::class,
static function (
LazyLoadingInterface $proxy,
string $method,
array $params,
?Closure & $initializer,
array $properties
) use ($initialCounter): bool {
$initializer = null;

$properties['counter'] = $initialCounter;

return true;
}
);

$increment = random_int(1001, 10000);

try {
$proxy->increment($increment);
$this->fail('RuntimeException expected');
} catch (RuntimeException $e) {
// Nothing to do
}

self::assertSame($initialCounter + $increment, $proxy->counter);
}

private static function isPropertyInitialized(object $object, ReflectionProperty $property): bool
{
return array_key_exists(
($property->isProtected() ? "\0*\0" : '')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
use ProxyManagerTestAsset\ClassWithPublicStringTypedProperty;
use ProxyManagerTestAsset\ClassWithSelfHint;
use ProxyManagerTestAsset\EmptyClass;
use ProxyManagerTestAsset\NeverCounter;
use ProxyManagerTestAsset\OtherObjectAccessClass;
use ProxyManagerTestAsset\VoidCounter;
use ReflectionClass;
use ReflectionProperty;
use RuntimeException;
use stdClass;

use function array_values;
Expand Down Expand Up @@ -695,6 +697,30 @@ public function testWillExecuteLogicInAVoidMethod(): void
self::assertSame($increment, $proxy->counter);
}

/**
* @requires PHP 8.1
*
* @psalm-suppress UndefinedClass Class, interface or enum named never does not exist
*/
public function testWillExecuteLogicInANeverMethod(): void
{
$proxy = (new LazyLoadingValueHolderFactory())->createProxy(
NeverCounter::class,
$this->createInitializer(NeverCounter::class, new NeverCounter())
);

$increment = random_int(100, 1000);

try {
$proxy->increment($increment);
$this->fail('RuntimeException expected');
} catch (RuntimeException $e) {
// Do nothing
}

self::assertSame($increment, $proxy->counter);
}

public function getMethodsThatAccessPropertiesOnOtherObjectsInTheSameScope(): Generator
{
foreach ((new ReflectionClass(OtherObjectAccessClass::class))->getProperties() as $property) {
Expand Down
16 changes: 16 additions & 0 deletions tests/ProxyManagerTest/Functional/NullObjectFunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
use ProxyManagerTestAsset\ClassWithPublicStringTypedProperty;
use ProxyManagerTestAsset\ClassWithSelfHint;
use ProxyManagerTestAsset\EmptyClass;
use ProxyManagerTestAsset\NeverCounter;
use ProxyManagerTestAsset\VoidCounter;
use ReflectionProperty;
use stdClass;
use TypeError;

use function array_values;
use function assert;
Expand Down Expand Up @@ -126,6 +128,20 @@ public function testPropertyUnset(NullObjectInterface $proxy, string $publicProp
self::assertFalse(isset($proxy->$publicProperty));
}

/**
* @requires PHP 8.1
*/
public function testNeverReturningMethodCalls(): void
{
$proxy = (new NullObjectFactory())->createProxy(NeverCounter::class);
$method = [$proxy, 'increment'];

self::assertIsCallable($method);

$this->expectException(TypeError::class);
$method(random_int(10, 1000));
}

/**
* Generates a list of object | invoked method | parameters | expected result
*
Expand Down
26 changes: 26 additions & 0 deletions tests/ProxyManagerTest/Functional/RemoteObjectFunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use ProxyManagerTestAsset\ClassWithPublicStringNullableTypedProperty;
use ProxyManagerTestAsset\ClassWithPublicStringTypedProperty;
use ProxyManagerTestAsset\ClassWithSelfHint;
use ProxyManagerTestAsset\NeverCounter;
use ProxyManagerTestAsset\OtherObjectAccessClass;
use ProxyManagerTestAsset\RemoteProxy\BazServiceInterface;
use ProxyManagerTestAsset\RemoteProxy\Foo;
Expand All @@ -26,6 +27,7 @@
use ProxyManagerTestAsset\RemoteProxy\VariadicArgumentsServiceInterface;
use ProxyManagerTestAsset\VoidCounter;
use ReflectionClass;
use RuntimeException;
use stdClass;

use function assert;
Expand Down Expand Up @@ -403,6 +405,30 @@ public function testWillExecuteLogicInAVoidMethod(): void
$proxy->increment($increment);
}

/**
* @requires PHP 8.1
*/
public function testWillExecuteLogicInANeverMethod(): void
{
$adapter = $this->createMock(AdapterInterface::class);

$increment = random_int(10, 1000);

$adapter
->expects(self::once())
->method('call')
->with(NeverCounter::class, 'increment', [$increment])
->willThrowException(new RuntimeException());

$proxy = clone (new RemoteObjectFactory($adapter))
->createProxy(NeverCounter::class);

$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('');

$proxy->increment($increment);
}

public function getMethodsThatAccessPropertiesOnOtherObjectsInTheSameScope(): Generator
{
foreach ((new ReflectionClass(OtherObjectAccessClass::class))->getProperties() as $property) {
Expand Down
21 changes: 21 additions & 0 deletions tests/ProxyManagerTestAsset/NeverCounter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace ProxyManagerTestAsset;

use RuntimeException;

class NeverCounter
{
/**
* @var int
*/
public $counter = 0;

public function increment(int $amount) : never
{
$this->counter += $amount;
throw new RuntimeException();
}
}

0 comments on commit 0232ad5

Please sign in to comment.