Skip to content

Commit 120bc98

Browse files
authored
Support named arguments when resolving template parameters
1 parent f5f18ae commit 120bc98

File tree

4 files changed

+51
-6
lines changed

4 files changed

+51
-6
lines changed

src/Reflection/GenericParametersAcceptorResolver.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class GenericParametersAcceptorResolver
1212

1313
/**
1414
* @api
15-
* @param Type[] $argTypes
15+
* @param array<int|string, Type> $argTypes
1616
*/
1717
public static function resolve(array $argTypes, ParametersAcceptor $parametersAcceptor): ParametersAcceptor
1818
{
@@ -21,6 +21,8 @@ public static function resolve(array $argTypes, ParametersAcceptor $parametersAc
2121
foreach ($parametersAcceptor->getParameters() as $i => $param) {
2222
if (isset($argTypes[$i])) {
2323
$argType = $argTypes[$i];
24+
} elseif (isset($argTypes[$param->getName()])) {
25+
$argType = $argTypes[$param->getName()];
2426
} elseif ($param->getDefaultValue() !== null) {
2527
$argType = $param->getDefaultValue();
2628
} else {

src/Reflection/ParametersAcceptorSelector.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PHPStan\Type\Type;
1919
use PHPStan\Type\TypeCombinator;
2020
use PHPStan\Type\UnionType;
21+
use function array_key_last;
2122
use function array_slice;
2223
use function count;
2324
use function sprintf;
@@ -161,21 +162,22 @@ public static function selectFromArgs(
161162
}
162163
}
163164

164-
foreach ($args as $arg) {
165+
foreach ($args as $i => $arg) {
165166
$type = $scope->getType($arg->value);
167+
$index = $arg->name !== null ? $arg->name->toString() : $i;
166168
if ($arg->unpack) {
167169
$unpack = true;
168-
$types[] = $type->getIterableValueType();
170+
$types[$index] = $type->getIterableValueType();
169171
} else {
170-
$types[] = $type;
172+
$types[$index] = $type;
171173
}
172174
}
173175

174176
return self::selectFromTypes($types, $parametersAcceptors, $unpack);
175177
}
176178

177179
/**
178-
* @param Type[] $types
180+
* @param array<int|string, Type> $types
179181
* @param ParametersAcceptor[] $parametersAcceptors
180182
*/
181183
public static function selectFromTypes(
@@ -246,7 +248,7 @@ public static function selectFromTypes(
246248
break;
247249
}
248250

249-
$type = $types[count($types) - 1];
251+
$type = $types[array_key_last($types)];
250252
} else {
251253
$type = $types[$i];
252254
}

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,11 @@ public function dataFileAsserts(): iterable
846846

847847
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6917.php');
848848
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6936-limit.php');
849+
850+
if (PHP_VERSION_ID >= 80000) {
851+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-5262.php');
852+
}
853+
849854
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6927.php');
850855
}
851856

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug5262;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @template T of TestBase
9+
* @param class-string<T> $testclass
10+
* @return T
11+
*/
12+
function test(bool $optional = false, string $testclass = TestBase::class): TestBase
13+
{
14+
return new $testclass();
15+
}
16+
17+
class TestBase
18+
{
19+
}
20+
21+
class TestChild extends TestBase
22+
{
23+
public function hello(): string
24+
{
25+
return 'world';
26+
}
27+
}
28+
29+
function runTest(): void
30+
{
31+
assertType('Bug5262\TestChild', test(false, TestChild::class));
32+
assertType('Bug5262\TestChild', test(false, testclass: TestChild::class));
33+
assertType('Bug5262\TestChild', test(optional: false, testclass: TestChild::class));
34+
assertType('Bug5262\TestChild', test(testclass: TestChild::class, optional: false));
35+
assertType('Bug5262\TestChild', test(testclass: TestChild::class));
36+
}

0 commit comments

Comments
 (0)