Skip to content

Commit db5b675

Browse files
committed
Ignore @no-named-arguments in the native type of variadic parameters
The native type of a variadic parameter used acceptsNamedArguments(), which comes from the @no-named-arguments PHPDoc tag. That contradicts getNativeType(), which is documented as ignoring PHPDoc, and makes an @phpstan-assert on such a parameter report as redundant under treatPhpDocTypesAsCertain: false. Only the PHPDoc-aware type now uses acceptsNamedArguments(). The native type keeps string keys whenever the PHP version supports named arguments.
1 parent acd0511 commit db5b675

5 files changed

Lines changed: 52 additions & 6 deletions

File tree

‎src/Analyser/MutatingScope.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2240,7 +2240,7 @@ private function enterFunctionLike(
22402240

22412241
$nativeParameterType = $parameter->getNativeType();
22422242
if ($parameter->isVariadic()) {
2243-
if (!$this->getPhpVersion()->supportsNamedArguments()->no() && $functionReflection->acceptsNamedArguments()->yes()) {
2243+
if (!$this->getPhpVersion()->supportsNamedArguments()->no()) {
22442244
$nativeParameterType = new ArrayType(new UnionType([IntegerRangeType::createAllGreaterThanOrEqualTo(0), new StringType()]), $nativeParameterType);
22452245
} else {
22462246
$nativeParameterType = new IntersectionType([new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), $nativeParameterType), new AccessoryArrayListType()]);

‎tests/PHPStan/Analyser/nsrt/no-named-arguments.php‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
function noNamedArgumentsInFunction(float ...$args)
1212
{
1313
assertType('list<float>', $args);
14-
assertNativeType('list<float>', $args);
14+
assertNativeType('array<int<0, max>|string, float>', $args);
1515
}
1616

1717
class Baz extends Foo implements Bar
@@ -22,19 +22,19 @@ class Baz extends Foo implements Bar
2222
public function noNamedArgumentsInMethod(float ...$args)
2323
{
2424
assertType('list<float>', $args);
25-
assertNativeType('list<float>', $args);
25+
assertNativeType('array<int<0, max>|string, float>', $args);
2626
}
2727

2828
public function noNamedArgumentsInParent(float ...$args)
2929
{
3030
assertType('list<float>', $args);
31-
assertNativeType('list<float>', $args);
31+
assertNativeType('array<int<0, max>|string, float>', $args);
3232
}
3333

3434
public function noNamedArgumentsInInterface(float ...$args)
3535
{
3636
assertType('list<float>', $args);
37-
assertNativeType('list<float>', $args);
37+
assertNativeType('array<int<0, max>|string, float>', $args);
3838
}
3939
}
4040

‎tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRuleTest.php‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,13 @@ public function testInTrait(): void
207207
]);
208208
}
209209

210+
#[RequiresPhp('>= 8.0.0')]
211+
public function testNoNamedArgumentsNativeTypeWithUncertainPhpDocTypes(): void
212+
{
213+
$this->treatPhpDocTypesAsCertain = false;
214+
$this->analyse([__DIR__ . '/data/no-named-arguments-native-type.php'], []);
215+
}
216+
210217
public static function getAdditionalConfigFiles(): array
211218
{
212219
return [
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php // lint >= 8.0
2+
declare(strict_types = 1);
3+
4+
namespace NoNamedArgumentsNativeType;
5+
6+
final class QueryBuilder
7+
{
8+
9+
/**
10+
* @no-named-arguments
11+
*/
12+
public function select(mixed ...$select): void
13+
{
14+
self::validateVariadicParameter($select);
15+
}
16+
17+
/**
18+
* @no-named-arguments
19+
*/
20+
public function groupBy(string ...$groupBy): void
21+
{
22+
self::validateVariadicParameter($groupBy);
23+
}
24+
25+
/**
26+
* @template TItem
27+
* @param TItem[] $parameter
28+
* @phpstan-assert list<TItem> $parameter
29+
*/
30+
private static function validateVariadicParameter(array $parameter): void
31+
{
32+
if (array_is_list($parameter)) {
33+
return;
34+
}
35+
36+
throw new \InvalidArgumentException();
37+
}
38+
39+
}

‎turbo-ext/src/MutatingScope.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4513,7 +4513,7 @@ class MutatingScope
45134513
if (UNEXPECTED(nativeParameterType.isUndef())) return zv::Val();
45144514
if (zend_is_true(isVariadic.raw())) {
45154515
bool named;
4516-
if (UNEXPECTED(!acceptsNamedArgumentsHere(reflection, named))) return zv::Val();
4516+
if (UNEXPECTED(!phpVersionSupportsNamedArguments(named))) return zv::Val();
45174517
zv::Val wrapped = variadicArrayType(nativeParameterType.raw(), named);
45184518
if (UNEXPECTED(wrapped.isUndef())) return zv::Val();
45194519
nativeParameterType = std::move(wrapped);

0 commit comments

Comments
 (0)