diff --git a/src/Analyser/ArgumentsNormalizer.php b/src/Analyser/ArgumentsNormalizer.php index 6c254df7632..ae6fb6511ca 100644 --- a/src/Analyser/ArgumentsNormalizer.php +++ b/src/Analyser/ArgumentsNormalizer.php @@ -403,7 +403,7 @@ public static function reorderArgs(ParametersAcceptor $parametersAcceptor, array continue; } if (!array_key_exists($j, $signatureParameters)) { - throw new ShouldNotHappenException('Parameter signatures cannot have holes'); + return null; } $parameter = $signatureParameters[$j]; diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 803d37fe8c9..0763f789a5c 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -1563,6 +1563,13 @@ public function testBug14550(): void $this->assertNotEmpty($errors); } + public function testBug14596(): void + { + // crash + $errors = $this->runAnalyse(__DIR__ . '/data/bug-14596.php'); + $this->assertNotEmpty($errors); + } + /** * @param string[]|null $allAnalysedFiles * @return list diff --git a/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php b/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php index b2cc10be5da..a9226fc3131 100644 --- a/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php +++ b/tests/PHPStan/Analyser/ArgumentsNormalizerTest.php @@ -323,6 +323,33 @@ public static function dataReorderInvalid(): iterable [new StringType(), 'three'], ], ]; + + // positional arg after named arg with variadic parameter + yield [ + [ + ['value', false, false, null], + ['values', true, true, new StringType()], + ], + [ + [new IntegerType(), null], + [new IntegerType(), null], + [new IntegerType(), null], + [new StringType(), 'd'], + [new IntegerType(), null], + ], + ]; + + // positional arg after named arg without variadic parameter + yield [ + [ + ['one', false, false, null], + ], + [ + [new IntegerType(), null], + [new StringType(), 'd'], + [new IntegerType(), null], + ], + ]; } /** diff --git a/tests/PHPStan/Analyser/data/bug-14596.php b/tests/PHPStan/Analyser/data/bug-14596.php new file mode 100644 index 00000000000..8904c0c8059 --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-14596.php @@ -0,0 +1,34 @@ +bar(1, 2, 3, d: 'foo', 5); + +// static method call +Foo::baz(1, 2, 3, d: 'foo', 5); + +// constructor +new Foo(1, 2, 3, d: 'foo', 5); + +// closure +$closure = function (int $a, int $b, int $c, string ...$rest): void {}; +$closure(1, 2, 3, d: 'foo', 5); + +// call_user_func +call_user_func('Bug14596\foo', 1, 2, 3, d: 'foo', 5); diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php index 141f7fbb281..b785aac506e 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php @@ -4102,4 +4102,18 @@ public function testBug8048(): void $this->analyse([__DIR__ . '/data/bug-8048.php'], []); } + #[RequiresPhp('>= 8.0.0')] + public function testBug14596(): void + { + $this->checkThisOnly = false; + $this->checkNullables = true; + $this->checkUnionTypes = true; + $this->analyse([__DIR__ . '/data/bug-14596.php'], [ + [ + 'Named argument cannot be followed by a positional argument.', + 11, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php index 076e4770e18..36c036efecf 100644 --- a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php @@ -1037,4 +1037,16 @@ public function testBug11894(): void $this->analyse([__DIR__ . '/data/bug-11894.php'], []); } + #[RequiresPhp('>= 8.0.0')] + public function testBug14596(): void + { + $this->checkThisOnly = false; + $this->analyse([__DIR__ . '/data/bug-14596.php'], [ + [ + 'Named argument cannot be followed by a positional argument.', + 12, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/bug-14596.php b/tests/PHPStan/Rules/Methods/data/bug-14596.php new file mode 100644 index 00000000000..f35305cdc31 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-14596.php @@ -0,0 +1,13 @@ +bar(1, 2, 3, d: 'foo', 5); + Foo::baz(1, 2, 3, d: 'foo', 5); +};