Skip to content

Commit e3abfd9

Browse files
committed
RegexArrayShapeMatcher - more precise subject types
1 parent 12a0b4e commit e3abfd9

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

src/Type/Php/RegexArrayShapeMatcher.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
114114
}
115115
[$groupList, $markVerbs] = $parseResult;
116116

117+
if ($groupList === [] && $markVerbs === []) {
118+
$rawRegex = $this->regexExpressionHelper->removeDelimitersAndModifiers($regex);
119+
$type = $this->matchRegex('{('.$rawRegex.')}', $flags, $wasMatched, $matchesAll);
120+
if ($type === null) {
121+
return null;
122+
}
123+
return $type->shiftArray();
124+
}
125+
117126
$regexGroupList = new RegexGroupList($groupList);
118127
$trailingOptionals = $regexGroupList->countTrailingOptionals();
119128
$onlyOptionalTopLevelGroup = $regexGroupList->getOnlyOptionalTopLevelGroup();

test.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
use function PHPStan\Testing\assertType;
4+
5+
/** @return non-empty-string|null */
6+
function bug12749(string $str): ?string
7+
{
8+
if (preg_match('/[A-Z]/', $str, $match)) {
9+
assertType('array{non-empty-string}', $match);
10+
return $match[0];
11+
}
12+
return null;
13+
}
14+
15+
/** @return non-falsy-string|null */
16+
function doFoo(string $str): ?string
17+
{
18+
if (preg_match('/[A-Z]{2,}/', $str, $match)) {
19+
assertType('array{non-falsy-string}', $match);
20+
return $match[0];
21+
}
22+
return null;
23+
}
24+
25+
/** @return non-falsy-string|null */
26+
function doBar(string $str): ?string
27+
{
28+
if (preg_match('/[0-9][A-Z]/', $str, $match)) {
29+
assertType('array{non-falsy-string}', $match);
30+
return $match[0];
31+
}
32+
return null;
33+
}
34+
35+
/** @return non-empty-string|null */
36+
function doFooBar(string $str): ?string
37+
{
38+
if (preg_match('/[0-9][A-Z]?/', $str, $match)) {
39+
assertType('array{non-empty-string}', $match);
40+
return $match[0];
41+
}
42+
return null;
43+
}
44+
45+
/** @return non-falsy-string|null */
46+
function doFooBar2(string $str): ?string
47+
{
48+
if (preg_match('/[0-9]?[A-Z]/', $str, $match)) {
49+
assertType('array{non-falsy-string}', $match);
50+
return $match[0];
51+
}
52+
return null;
53+
}

tests/PHPStan/Analyser/nsrt/preg_match_shapes.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,3 +960,11 @@ function bug11744(string $string): void
960960
}
961961
assertType('array{0: string, 1: non-empty-string, 2?: non-falsy-string}', $matches);
962962
}
963+
964+
/** @return non-empty-string|null */
965+
function bug12749(string $str): void
966+
{
967+
if (preg_match('/[A-Z]/', $str, $match)) {
968+
assertType('string', $match);
969+
}
970+
}

0 commit comments

Comments
 (0)