Skip to content

Commit 0e54233

Browse files
authored
Merge branch refs/heads/2.1.x into 2.2.x
2 parents a10a9a2 + 2ccd7b9 commit 0e54233

File tree

8 files changed

+195
-2
lines changed

8 files changed

+195
-2
lines changed

phpstan-baseline.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ parameters:
8787
-
8888
rawMessage: 'Doing instanceof PHPStan\Type\Constant\ConstantStringType is error-prone and deprecated. Use Type::getConstantStrings() instead.'
8989
identifier: phpstanApi.instanceofType
90-
count: 4
90+
count: 5
9191
path: src/Analyser/TypeSpecifier.php
9292

9393
-

src/Analyser/TypeSpecifier.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,53 @@ public function specifyTypesInCondition(
920920
return $exprType;
921921
}
922922

923+
if (
924+
$issetExpr instanceof ArrayDimFetch
925+
&& $issetExpr->dim !== null
926+
) {
927+
$varType = $scope->getType($issetExpr->var);
928+
if (!$varType instanceof MixedType) {
929+
$dimType = $scope->getType($issetExpr->dim);
930+
931+
if ($dimType instanceof ConstantIntegerType || $dimType instanceof ConstantStringType) {
932+
$constantArrays = $varType->getConstantArrays();
933+
$typesToRemove = [];
934+
foreach ($constantArrays as $constantArray) {
935+
$hasOffset = $constantArray->hasOffsetValueType($dimType);
936+
if (!$hasOffset->yes() || !$constantArray->getOffsetValueType($dimType)->isNull()->no()) {
937+
continue;
938+
}
939+
940+
$typesToRemove[] = $constantArray;
941+
}
942+
943+
if ($typesToRemove !== []) {
944+
$typeToRemove = TypeCombinator::union(...$typesToRemove);
945+
946+
$result = $this->create(
947+
$issetExpr->var,
948+
$typeToRemove,
949+
TypeSpecifierContext::createFalse(),
950+
$scope,
951+
)->setRootExpr($expr);
952+
953+
if ($scope->hasExpressionType($issetExpr->var)->maybe()) {
954+
$result = $result->unionWith(
955+
$this->create(
956+
new IssetExpr($issetExpr->var),
957+
new NullType(),
958+
TypeSpecifierContext::createTruthy(),
959+
$scope,
960+
)->setRootExpr($expr),
961+
);
962+
}
963+
964+
return $result;
965+
}
966+
}
967+
}
968+
}
969+
923970
return new SpecifiedTypes();
924971
}
925972

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug10544;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Boo {
8+
/**
9+
* @param array{check1:bool,boo:string}|array{check2:bool,foo:string} $param
10+
*/
11+
public function foo(array $param): string {
12+
if (isset($param['check1'])) {
13+
assertType('array{check1: bool, boo: string}', $param);
14+
return $param['boo'];
15+
}
16+
assertType('array{check2: bool, foo: string}', $param);
17+
return $param['foo'];
18+
}
19+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug12401;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @param array{a: string, b: string}|array{c: string} $data
9+
*/
10+
function test(array $data): void {
11+
if (isset($data['a'])) {
12+
assertType('array{a: string, b: string}', $data);
13+
} else {
14+
assertType('array{c: string}', $data);
15+
}
16+
17+
if (isset($data['a'])) {
18+
assertType('array{a: string, b: string}', $data);
19+
} elseif (isset($data['c'])) {
20+
assertType('array{c: string}', $data);
21+
} else {
22+
assertType('*NEVER*', $data);
23+
}
24+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug5128;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @param array{a: string}|array{b: string} $array
9+
*/
10+
function a(array $array): string {
11+
if (isset($array['a'])) {
12+
assertType('array{a: string}', $array);
13+
return $array['a'];
14+
}
15+
16+
assertType('array{b: string}', $array);
17+
return $array['b'];
18+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug8724;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @phpstan-type NumberFilterStructure array{
9+
* type: 'equals'|'notEqual'|'lessThan'|'lessThanOrEqual'|'greaterThan'|'greaterThanOrEqual'|'inRange'|'blank'|'notBlank',
10+
* }
11+
* @phpstan-type CombinedNumberFilterStructure array{
12+
* operator: 'AND'|'OR'
13+
* }
14+
*/
15+
class HelloWorld
16+
{
17+
/** @param NumberFilterStructure|CombinedNumberFilterStructure $filter */
18+
public function test(array $filter): void
19+
{
20+
if (isset($filter['operator'])) {
21+
assertType("array{operator: 'AND'|'OR'}", $filter);
22+
return;
23+
}
24+
25+
assertType("array{type: 'blank'|'equals'|'greaterThan'|'greaterThanOrEqual'|'inRange'|'lessThan'|'lessThanOrEqual'|'notBlank'|'notEqual'}", $filter);
26+
echo $filter['type'];
27+
}
28+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug9908;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class HelloWorld
8+
{
9+
public function test(): void
10+
{
11+
$a = [];
12+
if (rand() % 2) {
13+
$a = ['bar' => 'string'];
14+
}
15+
16+
if (isset($a['bar'])) {
17+
$a['bar'] = 1;
18+
}
19+
20+
assertType("array{}|array{bar: 1}", $a);
21+
}
22+
23+
/**
24+
* @param array{bar?: int} $foo
25+
*/
26+
public function sayHello(array $foo): void
27+
{
28+
echo 'Hello' . print_r($foo, true);
29+
}
30+
31+
public function test2(): void
32+
{
33+
$a = [];
34+
if (rand() % 2) {
35+
$a = ['bar' => 'string'];
36+
}
37+
38+
if (isset($a['bar'])) {
39+
$a['bar'] = 1;
40+
}
41+
42+
$this->sayHello($a);
43+
}
44+
45+
/**
46+
* @param array{a: string, b: string}|array{a: string|null, c: string}|array{a?: string, d: string} $a
47+
*/
48+
public function moreTests($a): void
49+
{
50+
if (isset($a['a'])) {
51+
assertType("array{a: string, b: string}|array{a: string, c: string}|array{a: string, d: string}", $a);
52+
} else {
53+
// Could be "array{a: null, c: string}|array{d: string}"
54+
assertType("array{a: string|null, c: string}|array{a?: string, d: string}", $a);
55+
}
56+
}
57+
}

tests/PHPStan/Analyser/nsrt/tagged-unions.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function doFoo4(array $foo)
5555
if (isset($foo['C'])) {
5656
assertType("array{A: string, C: 1}", $foo);
5757
} else {
58-
assertType("array{A: int, B: 1}|array{A: string, C: 1}", $foo); // could be array{A: int, B: 1}
58+
assertType("array{A: int, B: 1}", $foo);
5959
}
6060

6161
assertType('array{A: int, B: 1}|array{A: string, C: 1}', $foo);

0 commit comments

Comments
 (0)