Skip to content

Commit 36f8650

Browse files
ondrejmirtesclaude
andcommitted
Broaden unsealed value in ConstantArrayType::generalizeValues()
`generalizeValues()` walked the explicit `valueTypes` only — for an unsealed source the unsealed value type (e.g. `'foo'`) survived unchanged, leaving the result inconsistent: explicit values generalized to `int`/`string`/etc. but the unsealed slot still carried a constant. Generalize the unsealed value too, mirroring the explicit loop. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3beaa09 commit 36f8650

2 files changed

Lines changed: 21 additions & 1 deletion

File tree

src/Type/Constant/ConstantArrayType.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2305,7 +2305,13 @@ public function generalizeValues(): self
23052305
$valueTypes[] = $valueType->generalize(GeneralizePrecision::lessSpecific());
23062306
}
23072307

2308-
return $this->recreate($this->keyTypes, $valueTypes, $this->nextAutoIndexes, $this->optionalKeys, $this->isList, $this->unsealed);
2308+
$unsealed = $this->unsealed;
2309+
if ($unsealed !== null) {
2310+
[$unsealedKey, $unsealedValue] = $unsealed;
2311+
$unsealed = [$unsealedKey, $unsealedValue->generalize(GeneralizePrecision::lessSpecific())];
2312+
}
2313+
2314+
return $this->recreate($this->keyTypes, $valueTypes, $this->nextAutoIndexes, $this->optionalKeys, $this->isList, $unsealed);
23092315
}
23102316

23112317
private function degradeToGeneralArray(): Type

tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,20 @@ public function testGeneralize(ConstantArrayType $type, GeneralizePrecision $pre
19991999
);
20002000
}
20012001

2002+
public function testGeneralizeValuesAlsoBroadensUnsealedValue(): void
2003+
{
2004+
$type = new ConstantArrayType(
2005+
[new ConstantStringType('a')],
2006+
[new ConstantIntegerType(1)],
2007+
unsealed: [new IntegerType(), new ConstantStringType('foo')],
2008+
);
2009+
2010+
$this->assertSame(
2011+
'array{a: int, ...<int, string>}',
2012+
$type->generalizeValues()->describe(VerbosityLevel::precise()),
2013+
);
2014+
}
2015+
20022016
public function testTraverseSimultaneouslyVisitsUnsealedValue(): void
20032017
{
20042018
$left = new ConstantArrayType(

0 commit comments

Comments
 (0)