Skip to content

Commit 0a219ab

Browse files
github-actions[bot]phpstan-bot
authored andcommitted
Fix phpstan/phpstan#10172: foreach over array dim fetch losing template type
- Skip HasOffsetValueType propagation to parent variable in specifyExpressionType when the variable has a template type - The root cause was that foreach's empty/non-empty scope split narrowed the parent variable through ArrayDimFetch, destroying the template identity - New regression test in tests/PHPStan/Analyser/nsrt/bug-10172.php
1 parent c36922b commit 0a219ab

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

src/Analyser/MutatingScope.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
use PHPStan\Type\ErrorType;
7979
use PHPStan\Type\ExpressionTypeResolverExtensionRegistry;
8080
use PHPStan\Type\GeneralizePrecision;
81+
use PHPStan\Type\Generic\TemplateType;
8182
use PHPStan\Type\Generic\TemplateTypeHelper;
8283
use PHPStan\Type\Generic\TemplateTypeMap;
8384
use PHPStan\Type\IntegerRangeType;
@@ -2731,7 +2732,7 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType,
27312732
if ($dimType->isInteger()->yes() || $dimType->isString()->yes()) {
27322733
$exprVarType = $scope->getType($expr->var);
27332734
$isArray = $exprVarType->isArray();
2734-
if (!$exprVarType instanceof MixedType && !$isArray->no()) {
2735+
if (!$exprVarType instanceof MixedType && !$isArray->no() && !$exprVarType instanceof TemplateType) {
27352736
$tooManyHasOffsetValueTypes = false;
27362737

27372738
$varType = $exprVarType;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug10172;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class HelloWorld
8+
{
9+
/**
10+
* @template T of array{data: array<mixed>}
11+
*
12+
* @param T $a
13+
*
14+
* @return T
15+
*/
16+
public function foo(array $a): array
17+
{
18+
assertType('T of array{data: array<mixed>} (method Bug10172\HelloWorld::foo(), argument)', $a);
19+
20+
foreach ($a['data'] as $i) {
21+
}
22+
23+
assertType('T of array{data: array<mixed>} (method Bug10172\HelloWorld::foo(), argument)', $a);
24+
25+
return $a;
26+
}
27+
}

0 commit comments

Comments
 (0)