Skip to content

Commit 006f585

Browse files
committed
Merge branch '5.2' into 5.3
* 5.2: [Form] Backport type fixes [Finder] Fix iterator return types [DependencyInjection] Support for intersection types
2 parents 64833ac + a533160 commit 006f585

File tree

13 files changed

+180
-8
lines changed

13 files changed

+180
-8
lines changed

Compiler/CheckTypeDeclarationsPass.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,13 @@ private function checkType(Definition $checkedDefinition, $value, \ReflectionPar
174174

175175
throw new InvalidParameterTypeException($this->currentId, $e->getCode(), $parameter);
176176
}
177+
if ($reflectionType instanceof \ReflectionIntersectionType) {
178+
foreach ($reflectionType->getTypes() as $t) {
179+
$this->checkType($checkedDefinition, $value, $parameter, $envPlaceholderUniquePrefix, $t);
180+
}
181+
182+
return;
183+
}
177184
if (!$reflectionType instanceof \ReflectionNamedType) {
178185
return;
179186
}

Dumper/Preloader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ private static function preloadType(?\ReflectionType $t, array &$preloaded): voi
117117
return;
118118
}
119119

120-
foreach ($t instanceof \ReflectionUnionType ? $t->getTypes() : [$t] as $t) {
120+
foreach (($t instanceof \ReflectionUnionType || $t instanceof \ReflectionIntersectionType) ? $t->getTypes() : [$t] as $t) {
121121
if (!$t->isBuiltin()) {
122122
self::doPreload($t instanceof \ReflectionNamedType ? $t->getName() : $t, $preloaded);
123123
}

LazyProxy/ProxyHelper.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,31 @@ public static function getTypeHint(\ReflectionFunctionAbstract $r, \ReflectionPa
3333
}
3434

3535
$types = [];
36+
$glue = '|';
37+
if ($type instanceof \ReflectionUnionType) {
38+
$reflectionTypes = $type->getTypes();
39+
} elseif ($type instanceof \ReflectionIntersectionType) {
40+
$reflectionTypes = $type->getTypes();
41+
$glue = '&';
42+
} elseif ($type instanceof \ReflectionNamedType) {
43+
$reflectionTypes = [$type];
44+
} else {
45+
return null;
46+
}
3647

37-
foreach ($type instanceof \ReflectionUnionType ? $type->getTypes() : [$type] as $type) {
38-
$name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
39-
48+
foreach ($reflectionTypes as $type) {
4049
if ($type->isBuiltin()) {
4150
if (!$noBuiltin) {
42-
$types[] = $name;
51+
$types[] = $type->getName();
4352
}
4453
continue;
4554
}
4655

47-
$lcName = strtolower($name);
56+
$lcName = strtolower($type->getName());
4857
$prefix = $noBuiltin ? '' : '\\';
4958

5059
if ('self' !== $lcName && 'parent' !== $lcName) {
51-
$types[] = '' !== $prefix ? $prefix.$name : $name;
60+
$types[] = $prefix.$type->getName();
5261
continue;
5362
}
5463
if (!$r instanceof \ReflectionMethod) {
@@ -61,6 +70,6 @@ public static function getTypeHint(\ReflectionFunctionAbstract $r, \ReflectionPa
6170
}
6271
}
6372

64-
return $types ? implode('|', $types) : null;
73+
return $types ? implode($glue, $types) : null;
6574
}
6675
}

Tests/Compiler/AutowirePassTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,25 @@ public function testTypeNotGuessableUnionType()
258258
$pass->process($container);
259259
}
260260

261+
/**
262+
* @requires PHP 8.1
263+
*/
264+
public function testTypeNotGuessableIntersectionType()
265+
{
266+
$this->expectException(AutowiringFailedException::class);
267+
$this->expectExceptionMessage('Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\IntersectionClasses::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface&Symfony\Component\DependencyInjection\Tests\Compiler\AnotherInterface" but this class was not found.');
268+
$container = new ContainerBuilder();
269+
270+
$container->register(CollisionInterface::class);
271+
$container->register(AnotherInterface::class);
272+
273+
$aDefinition = $container->register('a', IntersectionClasses::class);
274+
$aDefinition->setAutowired(true);
275+
276+
$pass = new AutowirePass();
277+
$pass->process($container);
278+
}
279+
261280
public function testTypeNotGuessableWithTypeSet()
262281
{
263282
$container = new ContainerBuilder();

Tests/Compiler/CheckTypeDeclarationsPassTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@
2929
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Deprecated;
3030
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo;
3131
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\FooObject;
32+
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\IntersectionConstructor;
3233
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\UnionConstructor;
3334
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Waldo;
35+
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\WaldoFoo;
3436
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Wobble;
3537
use Symfony\Component\ExpressionLanguage\Expression;
3638

@@ -950,4 +952,37 @@ public function testReferencePassesMixed()
950952

951953
$this->addToAssertionCount(1);
952954
}
955+
956+
/**
957+
* @requires PHP 8.1
958+
*/
959+
public function testIntersectionTypePassesWithReference()
960+
{
961+
$container = new ContainerBuilder();
962+
963+
$container->register('foo', WaldoFoo::class);
964+
$container->register('intersection', IntersectionConstructor::class)
965+
->setArguments([new Reference('foo')]);
966+
967+
(new CheckTypeDeclarationsPass(true))->process($container);
968+
969+
$this->addToAssertionCount(1);
970+
}
971+
972+
/**
973+
* @requires PHP 8.1
974+
*/
975+
public function testIntersectionTypeFailsWithReference()
976+
{
977+
$container = new ContainerBuilder();
978+
979+
$container->register('waldo', Waldo::class);
980+
$container->register('intersection', IntersectionConstructor::class)
981+
->setArguments([new Reference('waldo')]);
982+
983+
$this->expectException(InvalidArgumentException::class);
984+
$this->expectExceptionMessage('Invalid definition for service "intersection": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\IntersectionConstructor::__construct()" accepts "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo&Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\WaldoInterface", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Waldo" passed.');
985+
986+
(new CheckTypeDeclarationsPass(true))->process($container);
987+
}
953988
}

Tests/Dumper/PreloaderTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
use Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\Dummy;
2121
use Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\DummyWithInterface;
2222
use Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\E;
23+
use Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\F;
24+
use Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\G;
25+
use Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\IntersectionDummy;
2326
use Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\UnionDummy;
2427

2528
class PreloaderTest extends TestCase
@@ -72,4 +75,20 @@ public function testPreloadUnion()
7275
self::assertTrue(class_exists(D::class, false));
7376
self::assertTrue(class_exists(E::class, false));
7477
}
78+
79+
/**
80+
* @requires PHP 8.1
81+
*/
82+
public function testPreloadIntersection()
83+
{
84+
$r = new \ReflectionMethod(Preloader::class, 'doPreload');
85+
86+
$preloaded = [];
87+
88+
$r->invokeArgs(null, ['Symfony\Component\DependencyInjection\Tests\Fixtures\Preload\IntersectionDummy', &$preloaded]);
89+
90+
self::assertTrue(class_exists(IntersectionDummy::class, false));
91+
self::assertTrue(class_exists(F::class, false));
92+
self::assertTrue(class_exists(G::class, false));
93+
}
7594
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass;
4+
5+
class IntersectionConstructor
6+
{
7+
public function __construct(Foo&WaldoInterface $arg)
8+
{
9+
}
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass;
4+
5+
class WaldoFoo extends Foo implements WaldoInterface
6+
{
7+
}

Tests/Fixtures/Preload/F.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload;
13+
14+
final class F
15+
{
16+
}

Tests/Fixtures/Preload/G.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload;
13+
14+
final class G
15+
{
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Preload;
13+
14+
final class IntersectionDummy
15+
{
16+
public F&G $fg;
17+
}

Tests/Fixtures/includes/autowiring_classes.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
require __DIR__.'/uniontype_classes.php';
99
require __DIR__.'/autowiring_classes_80.php';
1010
}
11+
if (\PHP_VERSION_ID >= 80100) {
12+
require __DIR__.'/intersectiontype_classes.php';
13+
}
1114

1215
class Foo
1316
{
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
4+
5+
interface AnotherInterface
6+
{
7+
}
8+
9+
class IntersectionClasses
10+
{
11+
public function __construct(CollisionInterface&AnotherInterface $collision)
12+
{
13+
}
14+
}

0 commit comments

Comments
 (0)