Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@
use PHPStan\Type\ArrayType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\ClosureType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantFloatType;
Expand Down Expand Up @@ -4619,7 +4618,7 @@ private static function generalizeType(Type $a, Type $b): Type
$constantStrings[$key][] = $type;
continue;
}
if ($type instanceof ConstantArrayType) {
if ($type->isConstantArray()->yes()) {
$constantArrays[$key][] = $type;
continue;
}
Expand Down Expand Up @@ -4713,9 +4712,9 @@ private static function generalizeType(Type $a, Type $b): Type
$bArrays = $bValueType->getArrays();
if (
count($aArrays) === 1
&& !$aArrays[0] instanceof ConstantArrayType
&& $aArrays[0]->isConstantArray()->no()
&& count($bArrays) === 1
&& !$bArrays[0] instanceof ConstantArrayType
&& $bArrays[0]->isConstantArray()->no()
) {
$aDepth = self::getArrayDepth($aArrays[0]);
$bDepth = self::getArrayDepth($bArrays[0]);
Expand Down
3 changes: 1 addition & 2 deletions src/Reflection/Php/PhpClassReflectionExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
use PHPStan\ShouldNotHappenException;
use PHPStan\TrinaryLogic;
use PHPStan\Type\ArrayType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\Enum\EnumCaseObjectType;
Expand Down Expand Up @@ -946,7 +945,7 @@ private function inferAndCachePropertyTypes(
}

$propertyType = $propertyType->generalize(GeneralizePrecision::lessSpecific());
if ($propertyType instanceof ConstantArrayType) {
if ($propertyType->isConstantArray()->yes()) {
$propertyType = new ArrayType(new MixedType(true), new MixedType(true));
}

Expand Down
4 changes: 2 additions & 2 deletions src/Rules/RuleLevelHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ public function accepts(Type $acceptingType, Type $acceptedType, bool $strictTyp
$acceptedType->isArray()->yes()
&& $acceptingType->isArray()->yes()
&& !$acceptingType->isIterableAtLeastOnce()->yes()
&& count($acceptedType->getConstantArrays()) === 0
&& count($acceptingType->getConstantArrays()) === 0
&& $acceptedType->isConstantArray()->no()
&& $acceptingType->isConstantArray()->no()
) {
return self::accepts(
$acceptingType->getIterableKeyType(),
Expand Down
5 changes: 5 additions & 0 deletions src/Type/Accessory/AccessoryArrayListType.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isConstantArray(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
}

public function isOversizedArray(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/Accessory/NonEmptyArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isConstantArray(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
}

public function isOversizedArray(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/Accessory/OversizedArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isConstantArray(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
}

public function isOversizedArray(): TrinaryLogic
{
return TrinaryLogic::createYes();
Expand Down
15 changes: 10 additions & 5 deletions src/Type/ArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ public function isSuperTypeOf(Type $type): TrinaryLogic
public function equals(Type $type): bool
{
return $type instanceof self
&& !$type instanceof ConstantArrayType
&& $this->getItemType()->equals($type->getItemType())
&& $type->isConstantArray()->no()
&& $this->getItemType()->equals($type->getIterableValueType())
&& $this->keyType->equals($type->keyType);
}

Expand Down Expand Up @@ -238,6 +238,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isConstantArray(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

public function isOversizedArray(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
Expand Down Expand Up @@ -509,19 +514,19 @@ public function traverse(callable $cb): Type

public function tryRemove(Type $typeToRemove): ?Type
{
if ($typeToRemove instanceof ConstantArrayType && $typeToRemove->isIterableAtLeastOnce()->no()) {
if ($typeToRemove->isConstantArray()->yes() && $typeToRemove->isIterableAtLeastOnce()->no()) {
return TypeCombinator::intersect($this, new NonEmptyArrayType());
}

if ($typeToRemove instanceof NonEmptyArrayType) {
return new ConstantArrayType([], []);
}

if ($this instanceof ConstantArrayType && $typeToRemove instanceof HasOffsetType) {
if ($this->isConstantArray()->yes() && $typeToRemove instanceof HasOffsetType) {
return $this->unsetOffset($typeToRemove->getOffsetType());
}

if ($this instanceof ConstantArrayType && $typeToRemove instanceof HasOffsetValueType) {
if ($this->isConstantArray()->yes() && $typeToRemove instanceof HasOffsetValueType) {
return $this->unsetOffset($typeToRemove->getOffsetType());
}

Expand Down
5 changes: 5 additions & 0 deletions src/Type/Constant/ConstantArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,11 @@ public function getLastIterableValueType(): Type
return TypeCombinator::union(...$valueTypes);
}

public function isConstantArray(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function isList(): TrinaryLogic
{
if ($this->isList) {
Expand Down
5 changes: 5 additions & 0 deletions src/Type/IntersectionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,11 @@ public function isArray(): TrinaryLogic
return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isArray());
}

public function isConstantArray(): TrinaryLogic
{
return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isConstantArray());
}

public function isOversizedArray(): TrinaryLogic
{
return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isOversizedArray());
Expand Down
5 changes: 5 additions & 0 deletions src/Type/MixedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createMaybe();
}

public function isConstantArray(): TrinaryLogic
{
return $this->isArray();
}

public function isOversizedArray(): TrinaryLogic
{
if ($this->subtractedType !== null) {
Expand Down
3 changes: 1 addition & 2 deletions src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use PHPStan\Reflection\FunctionReflection;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\CallableType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\FunctionTypeSpecifyingExtension;
use function count;
use function strtolower;
Expand Down Expand Up @@ -49,7 +48,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
if (
$value instanceof Array_
&& count($value->items) === 2
&& $valueType instanceof ConstantArrayType
&& $valueType->isConstantArray()->yes()
&& !$valueType->isCallable()->no()
) {
if ($value->items[0] === null || $value->items[1] === null) {
Expand Down
4 changes: 2 additions & 2 deletions src/Type/Php/MinMaxFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,15 @@ private function compareTypes(
): ?Type
{
if (
$firstType instanceof ConstantArrayType
$firstType->isConstantArray()->yes()
&& $secondType instanceof ConstantScalarType
) {
return $secondType;
}

if (
$firstType instanceof ConstantScalarType
&& $secondType instanceof ConstantArrayType
&& $secondType->isConstantArray()->yes()
) {
return $firstType;
}
Expand Down
5 changes: 5 additions & 0 deletions src/Type/StaticType.php
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,11 @@ public function isArray(): TrinaryLogic
return $this->getStaticObjectType()->isArray();
}

public function isConstantArray(): TrinaryLogic
{
return $this->getStaticObjectType()->isConstantArray();
}

public function isOversizedArray(): TrinaryLogic
{
return $this->getStaticObjectType()->isOversizedArray();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/Traits/LateResolvableTypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ public function isArray(): TrinaryLogic
return $this->resolve()->isArray();
}

public function isConstantArray(): TrinaryLogic
{
return $this->resolve()->isConstantArray();
}

public function isOversizedArray(): TrinaryLogic
{
return $this->resolve()->isOversizedArray();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/Traits/MaybeArrayTypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createMaybe();
}

public function isConstantArray(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
}

public function isOversizedArray(): TrinaryLogic
{
return TrinaryLogic::createMaybe();
Expand Down
5 changes: 5 additions & 0 deletions src/Type/Traits/NonArrayTypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public function isArray(): TrinaryLogic
return TrinaryLogic::createNo();
}

public function isConstantArray(): TrinaryLogic
{
return TrinaryLogic::createNo();
}

public function isOversizedArray(): TrinaryLogic
{
return TrinaryLogic::createNo();
Expand Down
2 changes: 2 additions & 0 deletions src/Type/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ public function getLastIterableValueType(): Type;

public function isArray(): TrinaryLogic;

public function isConstantArray(): TrinaryLogic;

public function isOversizedArray(): TrinaryLogic;

public function isList(): TrinaryLogic;
Expand Down
5 changes: 5 additions & 0 deletions src/Type/UnionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,11 @@ public function isArray(): TrinaryLogic
return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isArray());
}

public function isConstantArray(): TrinaryLogic
{
return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isConstantArray());
}

public function isOversizedArray(): TrinaryLogic
{
return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isOversizedArray());
Expand Down
74 changes: 74 additions & 0 deletions tests/PHPStan/Type/MixedTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,80 @@ public function testSubstractedIsArray(MixedType $mixedType, Type $typeToSubtrac
);
}

public function dataSubstractedIsConstantArray(): array
{
return [
[
new MixedType(),
new ArrayType(new IntegerType(), new StringType()),
TrinaryLogic::createMaybe(),
],
[
new MixedType(),
new ArrayType(new StringType(), new StringType()),
TrinaryLogic::createMaybe(),
],
[
new MixedType(),
new ArrayType(new MixedType(), new MixedType()),
TrinaryLogic::createNo(),
],
[
new MixedType(),
new ConstantArrayType(
[new ConstantIntegerType(1)],
[new ConstantStringType('hello')],
),
TrinaryLogic::createMaybe(),
],
[
new MixedType(),
new ConstantArrayType([], []),
TrinaryLogic::createMaybe(),
],
[
new MixedType(),
new UnionType([new FloatType(), new ArrayType(new MixedType(), new MixedType())]),
TrinaryLogic::createNo(),
],
[
new MixedType(),
new UnionType([new FloatType(), new ArrayType(new StringType(), new MixedType())]),
TrinaryLogic::createMaybe(),
],
[
new MixedType(),
new UnionType([new FloatType(), new IntegerType()]),
TrinaryLogic::createMaybe(),
],
[
new MixedType(),
new FloatType(),
TrinaryLogic::createMaybe(),
],
[
new MixedType(true),
new FloatType(),
TrinaryLogic::createMaybe(),
],
];
}

/**
* @dataProvider dataSubstractedIsConstantArray
*/
public function testSubstractedIsConstantArray(MixedType $mixedType, Type $typeToSubtract, TrinaryLogic $expectedResult): void
{
$subtracted = $mixedType->subtract($typeToSubtract);
$actualResult = $subtracted->isConstantArray();

$this->assertSame(
$expectedResult->describe(),
$actualResult->describe(),
sprintf('%s -> isConstantArray()', $subtracted->describe(VerbosityLevel::precise())),
);
}

public function dataSubstractedIsString(): array
{
return [
Expand Down