Skip to content

Commit

Permalink
Do not generalize class-string during template type inference
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaud-lb committed Feb 26, 2022
1 parent dbbb721 commit 80c2c47
Show file tree
Hide file tree
Showing 39 changed files with 202 additions and 34 deletions.
6 changes: 6 additions & 0 deletions src/Type/Accessory/AccessoryLiteralStringType.php
Expand Up @@ -9,6 +9,7 @@
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\FloatType;
use PHPStan\Type\GeneralizePrecision;
use PHPStan\Type\IntegerType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\MixedType;
Expand Down Expand Up @@ -189,6 +190,11 @@ public function traverse(callable $cb): Type
return $this;
}

public function generalize(GeneralizePrecision $precision): Type
{
return new StringType();
}

public static function __set_state(array $properties): Type
{
return new self();
Expand Down
6 changes: 6 additions & 0 deletions src/Type/Accessory/AccessoryNonEmptyStringType.php
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\FloatType;
use PHPStan\Type\GeneralizePrecision;
use PHPStan\Type\IntegerType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\StringType;
Expand Down Expand Up @@ -185,6 +186,11 @@ public function traverse(callable $cb): Type
return $this;
}

public function generalize(GeneralizePrecision $precision): Type
{
return new StringType();
}

public static function __set_state(array $properties): Type
{
return new self();
Expand Down
6 changes: 6 additions & 0 deletions src/Type/Accessory/AccessoryNumericStringType.php
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\FloatType;
use PHPStan\Type\GeneralizePrecision;
use PHPStan\Type\IntegerType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\StringType;
Expand Down Expand Up @@ -181,6 +182,11 @@ public function traverse(callable $cb): Type
return $this;
}

public function generalize(GeneralizePrecision $precision): Type
{
return new StringType();
}

public static function __set_state(array $properties): Type
{
return new self();
Expand Down
2 changes: 2 additions & 0 deletions src/Type/Accessory/HasMethodType.php
Expand Up @@ -11,6 +11,7 @@
use PHPStan\TrinaryLogic;
use PHPStan\Type\CompoundType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\ObjectTypeTrait;
Expand All @@ -28,6 +29,7 @@ class HasMethodType implements AccessoryType, CompoundType
use NonGenericTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonRemoveableTypeTrait;
use NonGeneralizableTypeTrait;

/** @api */
public function __construct(private string $methodName)
Expand Down
2 changes: 2 additions & 0 deletions src/Type/Accessory/HasOffsetType.php
Expand Up @@ -11,6 +11,7 @@
use PHPStan\Type\Traits\MaybeCallableTypeTrait;
use PHPStan\Type\Traits\MaybeIterableTypeTrait;
use PHPStan\Type\Traits\MaybeObjectTypeTrait;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\TruthyBooleanTypeTrait;
Expand All @@ -30,6 +31,7 @@ class HasOffsetType implements CompoundType, AccessoryType
use NonGenericTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonRemoveableTypeTrait;
use NonGeneralizableTypeTrait;

/** @api */
public function __construct(private Type $offsetType)
Expand Down
2 changes: 2 additions & 0 deletions src/Type/Accessory/HasPropertyType.php
Expand Up @@ -7,6 +7,7 @@
use PHPStan\TrinaryLogic;
use PHPStan\Type\CompoundType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\ObjectTypeTrait;
Expand All @@ -23,6 +24,7 @@ class HasPropertyType implements AccessoryType, CompoundType
use NonGenericTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonRemoveableTypeTrait;
use NonGeneralizableTypeTrait;

/** @api */
public function __construct(private string $propertyName)
Expand Down
2 changes: 2 additions & 0 deletions src/Type/Accessory/NonEmptyArrayType.php
Expand Up @@ -10,6 +10,7 @@
use PHPStan\Type\IntersectionType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Traits\MaybeCallableTypeTrait;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
Expand All @@ -28,6 +29,7 @@ class NonEmptyArrayType implements CompoundType, AccessoryType
use NonGenericTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonRemoveableTypeTrait;
use NonGeneralizableTypeTrait;

/** @api */
public function __construct()
Expand Down
2 changes: 2 additions & 0 deletions src/Type/ArrayType.php
Expand Up @@ -18,6 +18,7 @@
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\Generic\TemplateTypeVariance;
use PHPStan\Type\Traits\MaybeCallableTypeTrait;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonTypeTrait;
Expand All @@ -36,6 +37,7 @@ class ArrayType implements Type
use NonObjectTypeTrait;
use UndecidedBooleanTypeTrait;
use UndecidedComparisonTypeTrait;
use NonGeneralizableTypeTrait;

private Type $keyType;

Expand Down
2 changes: 2 additions & 0 deletions src/Type/BooleanType.php
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\Traits\NonCallableTypeTrait;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
Expand All @@ -27,6 +28,7 @@ class BooleanType implements Type
use UndecidedComparisonTypeTrait;
use NonGenericTypeTrait;
use NonOffsetAccessibleTypeTrait;
use NonGeneralizableTypeTrait;

/** @api */
public function __construct()
Expand Down
2 changes: 2 additions & 0 deletions src/Type/CallableType.php
Expand Up @@ -16,6 +16,7 @@
use PHPStan\Type\Traits\MaybeIterableTypeTrait;
use PHPStan\Type\Traits\MaybeObjectTypeTrait;
use PHPStan\Type\Traits\MaybeOffsetAccessibleTypeTrait;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\TruthyBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
Expand All @@ -34,6 +35,7 @@ class CallableType implements CompoundType, ParametersAcceptor
use TruthyBooleanTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonRemoveableTypeTrait;
use NonGeneralizableTypeTrait;

/** @var array<int, ParameterReflection> */
private array $parameters;
Expand Down
2 changes: 2 additions & 0 deletions src/Type/ClosureType.php
Expand Up @@ -22,6 +22,7 @@
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\Generic\TemplateTypeHelper;
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonOffsetAccessibleTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
Expand All @@ -39,6 +40,7 @@ class ClosureType implements TypeWithClassName, ParametersAcceptor
use UndecidedComparisonTypeTrait;
use NonOffsetAccessibleTypeTrait;
use NonRemoveableTypeTrait;
use NonGeneralizableTypeTrait;

private ObjectType $objectType;

Expand Down
4 changes: 4 additions & 0 deletions src/Type/Constant/ConstantArrayType.php
Expand Up @@ -625,6 +625,10 @@ public function generalize(GeneralizePrecision $precision): Type
return $this;
}

if ($precision->isTemplateArgument()) {
return $this->traverse(static fn (Type $type) => $type->generalize($precision));
}

$arrayType = new ArrayType(
TypeUtils::generalizeType($this->getKeyType(), $precision),
TypeUtils::generalizeType($this->getItemType(), $precision),
Expand Down
2 changes: 2 additions & 0 deletions src/Type/FloatType.php
Expand Up @@ -7,6 +7,7 @@
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Traits\NonCallableTypeTrait;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
Expand All @@ -28,6 +29,7 @@ class FloatType implements Type
use NonGenericTypeTrait;
use NonOffsetAccessibleTypeTrait;
use NonRemoveableTypeTrait;
use NonGeneralizableTypeTrait;

/** @api */
public function __construct()
Expand Down
17 changes: 17 additions & 0 deletions src/Type/GeneralizePrecision.php
Expand Up @@ -7,6 +7,7 @@ class GeneralizePrecision

private const LESS_SPECIFIC = 1;
private const MORE_SPECIFIC = 2;
private const TEMPLATE_ARGUMENT = 3;

/** @var self[] */
private static array $registry;
Expand All @@ -33,9 +34,25 @@ public static function moreSpecific(): self
return self::create(self::MORE_SPECIFIC);
}

/** @api */
public static function templateArgument(): self
{
return self::create(self::TEMPLATE_ARGUMENT);
}

public function isLessSpecific(): bool
{
return $this->value === self::LESS_SPECIFIC;
}

public function isMoreSpecific(): bool
{
return $this->value === self::MORE_SPECIFIC;
}

public function isTemplateArgument(): bool
{
return $this->value === self::TEMPLATE_ARGUMENT;
}

}
23 changes: 0 additions & 23 deletions src/Type/Generic/TemplateTypeHelper.php
Expand Up @@ -2,11 +2,7 @@

namespace PHPStan\Type\Generic;

use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\ConstantType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\GeneralizePrecision;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeTraverser;

Expand Down Expand Up @@ -64,23 +60,4 @@ public static function toArgument(Type $type): Type
});
}

public static function generalizeType(Type $type): Type
{
return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type {
if ($type instanceof ConstantType && !$type instanceof ConstantArrayType) {
return $type->generalize(GeneralizePrecision::lessSpecific());
}

if ($type->isNonEmptyString()->yes()) {
return new StringType();
}

if ($type->isLiteralString()->yes()) {
return new StringType();
}

return $traverse($type);
});
}

}
3 changes: 2 additions & 1 deletion src/Type/Generic/TemplateTypeTrait.php
Expand Up @@ -3,6 +3,7 @@
namespace PHPStan\Type\Generic;

use PHPStan\TrinaryLogic;
use PHPStan\Type\GeneralizePrecision;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
Expand Down Expand Up @@ -194,7 +195,7 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
$resolvedBound = TemplateTypeHelper::resolveTemplateTypes($this->getBound(), $map);
if ($resolvedBound->isSuperTypeOf($receivedType)->yes()) {
return (new TemplateTypeMap([
$this->name => $this->shouldGeneralizeInferredType() ? TemplateTypeHelper::generalizeType($receivedType) : $receivedType,
$this->name => $this->shouldGeneralizeInferredType() ? $receivedType->generalize(GeneralizePrecision::templateArgument()) : $receivedType,
]))->union($map);
}

Expand Down
2 changes: 2 additions & 0 deletions src/Type/IntegerType.php
Expand Up @@ -6,6 +6,7 @@
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Traits\NonCallableTypeTrait;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
Expand All @@ -25,6 +26,7 @@ class IntegerType implements Type
use UndecidedComparisonTypeTrait;
use NonGenericTypeTrait;
use NonOffsetAccessibleTypeTrait;
use NonGeneralizableTypeTrait;

/** @api */
public function __construct()
Expand Down
5 changes: 5 additions & 0 deletions src/Type/IntersectionType.php
Expand Up @@ -22,6 +22,8 @@
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\Generic\TemplateTypeVariance;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use function array_map;
use function count;
use function implode;
Expand All @@ -34,6 +36,9 @@
class IntersectionType implements CompoundType
{

use NonRemoveableTypeTrait;
use NonGeneralizableTypeTrait;

/** @var Type[] */
private array $types;

Expand Down
2 changes: 2 additions & 0 deletions src/Type/IterableType.php
Expand Up @@ -12,6 +12,7 @@
use PHPStan\Type\Traits\MaybeCallableTypeTrait;
use PHPStan\Type\Traits\MaybeObjectTypeTrait;
use PHPStan\Type\Traits\MaybeOffsetAccessibleTypeTrait;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use Traversable;
Expand All @@ -27,6 +28,7 @@ class IterableType implements CompoundType
use MaybeOffsetAccessibleTypeTrait;
use UndecidedBooleanTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonGeneralizableTypeTrait;

/** @api */
public function __construct(
Expand Down
2 changes: 2 additions & 0 deletions src/Type/MixedType.php
Expand Up @@ -19,6 +19,7 @@
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Generic\TemplateMixedType;
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use function sprintf;
Expand All @@ -29,6 +30,7 @@ class MixedType implements CompoundType, SubtractableType

use NonGenericTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonGeneralizableTypeTrait;

private ?Type $subtractedType;

Expand Down
2 changes: 2 additions & 0 deletions src/Type/NeverType.php
Expand Up @@ -12,6 +12,7 @@
use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection;
use PHPStan\ShouldNotHappenException;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
Expand All @@ -25,6 +26,7 @@ class NeverType implements CompoundType
use NonGenericTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonRemoveableTypeTrait;
use NonGeneralizableTypeTrait;

/** @api */
public function __construct(private bool $isExplicit = false)
Expand Down

0 comments on commit 80c2c47

Please sign in to comment.