Skip to content

Commit e7652ad

Browse files
authored
Merge branch refs/heads/1.12.x into 2.0.x
2 parents 0471825 + d3a2a92 commit e7652ad

File tree

5 files changed

+127
-11
lines changed

5 files changed

+127
-11
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4775,18 +4775,29 @@ private function processArgs(
47754775
}
47764776

47774777
$argValue = $arg->value;
4778-
if ($argValue instanceof Variable && is_string($argValue->name)) {
4779-
if ($argValue->name !== 'this') {
4780-
$paramOutType = $this->getParameterOutExtensionsType($callLike, $calleeReflection, $currentParameter, $scope);
4781-
if ($paramOutType !== null) {
4782-
$byRefType = $paramOutType;
4783-
}
4784-
4785-
$nodeCallback(new VariableAssignNode($argValue, new TypeExpr($byRefType), false), $scope);
4786-
$scope = $scope->assignVariable($argValue->name, $byRefType, new MixedType());
4778+
if (!$argValue instanceof Variable || $argValue->name !== 'this') {
4779+
$paramOutType = $this->getParameterOutExtensionsType($callLike, $calleeReflection, $currentParameter, $scope);
4780+
if ($paramOutType !== null) {
4781+
$byRefType = $paramOutType;
47874782
}
4788-
} else {
4789-
$scope = $scope->invalidateExpression($argValue);
4783+
4784+
$result = $this->processAssignVar(
4785+
$scope,
4786+
$stmt,
4787+
$argValue,
4788+
new TypeExpr($byRefType),
4789+
static function (Node $node, Scope $scope) use ($nodeCallback): void {
4790+
if (!$node instanceof PropertyAssignNode && !$node instanceof VariableAssignNode) {
4791+
return;
4792+
}
4793+
4794+
$nodeCallback($node, $scope);
4795+
},
4796+
$context,
4797+
static fn (MutatingScope $scope): ExpressionResult => new ExpressionResult($scope, false, [], []),
4798+
true,
4799+
);
4800+
$scope = $result->getScope();
47904801
}
47914802
} elseif ($calleeReflection !== null && $calleeReflection->hasSideEffects()->yes()) {
47924803
$argType = $scope->getType($arg->value);

tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,21 @@ public function testTypesAssignedToProperties(): void
107107
'Property PropertiesAssignedTypes\AppendToArrayAccess::$collection2 (ArrayAccess<int, string>&Countable) does not accept Countable.',
108108
376,
109109
],
110+
[
111+
'Property PropertiesAssignedTypes\ParamOutAssign::$foo (list<string>) does not accept string.',
112+
400,
113+
'string is not a list.',
114+
],
115+
[
116+
'Property PropertiesAssignedTypes\ParamOutAssign::$foo2 (list<list<string>>) does not accept string.',
117+
410,
118+
'string is not a list.',
119+
],
120+
[
121+
'Property PropertiesAssignedTypes\ParamOutAssign::$foo2 (list<list<string>>) does not accept non-empty-list<list<string>|string>.',
122+
415,
123+
'list<string>|string might not be a list.',
124+
],
110125
]);
111126
}
112127

tests/PHPStan/Rules/Properties/data/properties-assigned-types.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,48 @@ public function foo(): void
376376
$this->collection2[] = 2;
377377
}
378378
}
379+
380+
class ParamOutAssign
381+
{
382+
383+
/** @var list<string> */
384+
private $foo;
385+
386+
/** @var list<list<string>> */
387+
private $foo2;
388+
389+
/**
390+
* @param mixed $a
391+
* @param-out string $a
392+
*/
393+
public function paramOut(&$a): void
394+
{
395+
396+
}
397+
398+
public function doFoo(): void
399+
{
400+
$this->paramOut($this->foo);
401+
}
402+
403+
public function doFoo2(): void
404+
{
405+
$this->paramOut($this->foo[0]);
406+
}
407+
408+
public function doBar(): void
409+
{
410+
$this->paramOut($this->foo2);
411+
}
412+
413+
public function doBar2(): void
414+
{
415+
$this->paramOut($this->foo2[0]);
416+
}
417+
418+
public function doBar3(): void
419+
{
420+
$this->paramOut($this->foo2[0][0]);
421+
}
422+
423+
}

tests/PHPStan/Rules/TooWideTypehints/TooWidePropertyTypeRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,9 @@ public function testRule(): void
5656
]);
5757
}
5858

59+
public function testBug11667(): void
60+
{
61+
$this->analyse([__DIR__ . '/data/bug-11667.php'], []);
62+
}
63+
5964
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Bug11667;
4+
5+
final class HelloWorld {
6+
/** @var list<string>|null */
7+
private $matches = null;
8+
9+
public function match(string $string): void {
10+
preg_match('/Hello (\w+)/', $string, $this->matches);
11+
}
12+
13+
/** @return list<string>|null */
14+
public function get(): ?array {
15+
return $this->matches;
16+
}
17+
}
18+
19+
final class HelloWorld2 {
20+
/** @var list<string>|null */
21+
private $matches = null;
22+
23+
public function match(string $string): void {
24+
$this->paramOut($this->matches);
25+
}
26+
27+
/**
28+
* @param mixed $a
29+
* @param-out list<string> $a
30+
*/
31+
public function paramOut(&$a): void
32+
{
33+
34+
}
35+
36+
/** @return list<string>|null */
37+
public function get(): ?array {
38+
return $this->matches;
39+
}
40+
}

0 commit comments

Comments
 (0)