Skip to content

Commit 08ed3e4

Browse files
committed
Prevent TypeCombinator::intersect() calls in MutatingScope-> specifyExpressionType()
1 parent d7ba1e3 commit 08ed3e4

File tree

6 files changed

+21
-14
lines changed

6 files changed

+21
-14
lines changed

src/Analyser/MutatingScope.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,7 +1857,10 @@ private function getTypeFromArrayDimFetch(
18571857
return $offsetAccessibleType;
18581858
}
18591859

1860-
if (!$offsetAccessibleType->isArray()->yes() && (new ObjectType(ArrayAccess::class))->isSuperTypeOf($offsetAccessibleType)->yes()) {
1860+
if (
1861+
!$offsetAccessibleType->isArray()->yes()
1862+
&& (new ObjectType(ArrayAccess::class))->isSuperTypeOf($offsetAccessibleType)->yes()
1863+
) {
18611864
return $this->getType(
18621865
new MethodCall(
18631866
$arrayDimFetch->var,
@@ -3368,11 +3371,15 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType,
33683371
$dimType = $scope->getType($expr->dim)->toArrayKey();
33693372
if ($dimType->isInteger()->yes() || $dimType->isString()->yes()) {
33703373
$exprVarType = $scope->getType($expr->var);
3371-
if (!$exprVarType instanceof MixedType && !$exprVarType->isArray()->no()) {
3372-
if ($dimType->isInteger()->yes()) {
3373-
$varType = TypeCombinator::intersect($exprVarType, StaticTypeFactory::intOffsetAccessibleType());
3374-
} else {
3375-
$varType = TypeCombinator::intersect($exprVarType, StaticTypeFactory::generalOffsetAccessibleType());
3374+
$isArray = $exprVarType->isArray();
3375+
if (!$exprVarType instanceof MixedType && !$isArray->no()) {
3376+
$varType = $exprVarType;
3377+
if (!$isArray->yes()) {
3378+
if ($dimType->isInteger()->yes()) {
3379+
$varType = TypeCombinator::intersect($exprVarType, StaticTypeFactory::intOffsetAccessibleType());
3380+
} else {
3381+
$varType = TypeCombinator::intersect($exprVarType, StaticTypeFactory::generalOffsetAccessibleType());
3382+
}
33763383
}
33773384

33783385
if ($dimType instanceof ConstantIntegerType || $dimType instanceof ConstantStringType) {

tests/PHPStan/Analyser/nsrt/bug-2911.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,6 @@ private function getResultSettings(array $settings): array
134134
function foo(array $array): void {
135135
$array['bar'] = 'string';
136136

137-
assertType("non-empty-array&hasOffsetValue('bar', 'string')", $array);
137+
assertType("non-empty-array<mixed>&hasOffsetValue('bar', 'string')", $array);
138138
}
139139
}

tests/PHPStan/Analyser/nsrt/composer-array-bug.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,17 @@ public function doFoo(): void
4747
}
4848
}
4949

50-
assertType("non-empty-array&hasOffsetValue('authors', mixed)", $this->config);
50+
assertType("non-empty-array<mixed>&hasOffsetValue('authors', mixed)", $this->config);
5151
assertType("mixed", $this->config['authors']);
5252

5353
if (empty($this->config['authors'])) {
5454
unset($this->config['authors']);
5555
assertType("array<mixed~'authors', mixed>", $this->config);
5656
} else {
57-
assertType("non-empty-array&hasOffsetValue('authors', mixed~(0|0.0|''|'0'|array{}|false|null))", $this->config);
57+
assertType("non-empty-array<mixed>&hasOffsetValue('authors', mixed~(0|0.0|''|'0'|array{}|false|null))", $this->config);
5858
}
5959

60-
assertType("array", $this->config);
60+
assertType("array<mixed>", $this->config);
6161
}
6262
}
6363

tests/PHPStan/Analyser/nsrt/superglobals.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ public function canBeOverwritten(): void
3131
public function canBePartlyOverwritten(): void
3232
{
3333
$GLOBALS['foo'] = 'foo';
34-
assertType("non-empty-array&hasOffsetValue('foo', 'foo')", $GLOBALS);
34+
assertType("non-empty-array<mixed>&hasOffsetValue('foo', 'foo')", $GLOBALS);
3535
assertNativeType("non-empty-array<mixed>&hasOffsetValue('foo', 'foo')", $GLOBALS);
3636
}
3737

3838
public function canBeNarrowed(): void
3939
{
4040
if (isset($GLOBALS['foo'])) {
41-
assertType("non-empty-array&hasOffsetValue('foo', mixed~null)", $GLOBALS);
41+
assertType("non-empty-array<mixed>&hasOffsetValue('foo', mixed~null)", $GLOBALS);
4242
assertNativeType("non-empty-array<mixed>&hasOffset('foo')", $GLOBALS); // https://github.com/phpstan/phpstan/issues/8395
4343
} else {
4444
assertType('array<mixed>', $GLOBALS);

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ public function testBug2911(): void
13181318
{
13191319
$this->analyse([__DIR__ . '/data/bug-2911.php'], [
13201320
[
1321-
'Parameter #1 $array of function Bug2911\bar expects array{bar: string}, non-empty-array given.',
1321+
'Parameter #1 $array of function Bug2911\bar expects array{bar: string}, non-empty-array<mixed> given.',
13221322
23,
13231323
],
13241324
]);

tests/PHPStan/Rules/Functions/data/bug-7156.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function foobar2(mixed $data): void
3232
throw new \RuntimeException();
3333
}
3434

35-
assertType("non-empty-array&hasOffsetValue('value', string)", $data);
35+
assertType("non-empty-array<mixed, mixed>&hasOffsetValue('value', string)", $data);
3636

3737
foo($data);
3838
}

0 commit comments

Comments
 (0)