Skip to content

Implement template default types #1835

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: 1.9.x
Choose a base branch
from
Draft
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
5 changes: 5 additions & 0 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -5169,6 +5169,11 @@ private function exactInstantiation(New_ $node, string $className): ?Type
$list[] = $templateType;
continue;
}
$default = $tag->getDefault();
if ($default !== null) {
$list[] = $default;
continue;
}
$bound = $tag->getBound();
if ($bound instanceof MixedType && $bound->isExplicitMixed()) {
$bound = new MixedType(false);
Expand Down
5 changes: 4 additions & 1 deletion src/PhpDoc/PhpDocNodeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,12 @@ public function resolveTemplateTags(PhpDocNode $phpDocNode, NameScope $nameScope
}
}

$nameScopeWithoutCurrent = $nameScope->unsetTemplateType($valueNode->name);

$resolved[$valueNode->name] = new TemplateTag(
$valueNode->name,
$valueNode->bound !== null ? $this->typeNodeResolver->resolve($valueNode->bound, $nameScope->unsetTemplateType($valueNode->name)) : new MixedType(true),
$valueNode->bound !== null ? $this->typeNodeResolver->resolve($valueNode->bound, $nameScopeWithoutCurrent) : new MixedType(true),
$valueNode->default !== null ? $this->typeNodeResolver->resolve($valueNode->default, $nameScopeWithoutCurrent) : null,
$variance,
);
$resolvedPrefix[$valueNode->name] = $prefix;
Expand Down
7 changes: 6 additions & 1 deletion src/PhpDoc/Tag/TemplateTag.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
class TemplateTag
{

public function __construct(private string $name, private Type $bound, private TemplateTypeVariance $variance)
public function __construct(private string $name, private Type $bound, private ?Type $default, private TemplateTypeVariance $variance)
{
}

Expand All @@ -23,6 +23,11 @@ public function getBound(): Type
return $this->bound;
}

public function getDefault(): ?Type
{
return $this->default;
}

public function getVariance(): TemplateTypeVariance
{
return $this->variance;
Expand Down
11 changes: 11 additions & 0 deletions src/PhpDoc/TypeNodeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
use PHPStan\Type\FloatType;
use PHPStan\Type\Generic\GenericClassStringType;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\IntegerRangeType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\IntersectionType;
Expand Down Expand Up @@ -92,6 +93,7 @@
use Traversable;
use function array_key_exists;
use function array_map;
use function array_values;
use function count;
use function explode;
use function get_class;
Expand Down Expand Up @@ -683,6 +685,15 @@ private function resolveGenericTypeNode(GenericTypeNode $typeNode, NameScope $na

$classReflection = $this->getReflectionProvider()->getClass($mainType->getClassName());
if ($classReflection->isGeneric()) {
$templateTypes = array_values($classReflection->getTemplateTypeMap()->getTypes());
for ($i = count($genericTypes), $templateTypesCount = count($templateTypes); $i < $templateTypesCount; $i++) {
$templateType = $templateTypes[$i];
if (!$templateType instanceof TemplateType || $templateType->getDefault() === null) {
continue;
}
$genericTypes[] = $templateType->getDefault();
}

if (in_array($mainType->getClassName(), [
Traversable::class,
IteratorAggregate::class,
Expand Down
4 changes: 2 additions & 2 deletions src/Reflection/ClassReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ public function typeMapFromList(array $types): TemplateTypeMap
$map = [];
$i = 0;
foreach ($resolvedPhpDoc->getTemplateTags() as $tag) {
$map[$tag->getName()] = $types[$i] ?? new ErrorType();
$map[$tag->getName()] = $types[$i] ?? $tag->getDefault() ?? new ErrorType();
$i++;
}

Expand All @@ -1272,7 +1272,7 @@ public function typeMapToList(TemplateTypeMap $typeMap): array

$list = [];
foreach ($resolvedPhpDoc->getTemplateTags() as $tag) {
$list[] = $typeMap->getType($tag->getName()) ?? $tag->getBound();
$list[] = $typeMap->getType($tag->getName()) ?? $tag->getDefault() ?? $tag->getBound();
}

return $list;
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/FunctionCallParametersCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ static function (Type $type, callable $traverse) use (&$returnTemplateTypes): Ty
$type = $type->resolve();
}

if ($type instanceof TemplateType) {
if ($type instanceof TemplateType && $type->getDefault() === null) {
$returnTemplateTypes[$type->getName()] = true;
return $type;
}
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PHPStan\Type\ArrayType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;

/** @api */
final class TemplateArrayType extends ArrayType implements TemplateType
Expand All @@ -19,6 +20,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
ArrayType $bound,
?Type $default,
)
{
parent::__construct($bound->getKeyType(), $bound->getItemType());
Expand All @@ -27,6 +29,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

protected function shouldGeneralizeInferredType(): bool
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateBenevolentUnionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
BenevolentUnionType $bound,
?Type $default,
)
{
parent::__construct($bound->getTypes());
Expand All @@ -27,6 +28,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

/** @param Type[] $types */
Expand All @@ -38,6 +40,7 @@ public function withTypes(array $types): self
$this->variance,
$this->name,
new BenevolentUnionType($types),
$this->default,
);
}

Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateBooleanType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PHPStan\Type\BooleanType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;

/** @api */
final class TemplateBooleanType extends BooleanType implements TemplateType
Expand All @@ -19,6 +20,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
BooleanType $bound,
?Type $default,
)
{
parent::__construct();
Expand All @@ -27,6 +29,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

protected function shouldGeneralizeInferredType(): bool
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateConstantArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;

/** @api */
final class TemplateConstantArrayType extends ConstantArrayType implements TemplateType
Expand All @@ -19,6 +20,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
ConstantArrayType $bound,
?Type $default,
)
{
parent::__construct($bound->getKeyTypes(), $bound->getValueTypes(), $bound->getNextAutoIndexes(), $bound->getOptionalKeys(), $bound->isList()->yes());
Expand All @@ -27,6 +29,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

protected function shouldGeneralizeInferredType(): bool
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateConstantIntegerType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;

/** @api */
final class TemplateConstantIntegerType extends ConstantIntegerType implements TemplateType
Expand All @@ -19,6 +20,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
ConstantIntegerType $bound,
?Type $default,
)
{
parent::__construct($bound->getValue());
Expand All @@ -27,6 +29,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

protected function shouldGeneralizeInferredType(): bool
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateConstantStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;

/** @api */
final class TemplateConstantStringType extends ConstantStringType implements TemplateType
Expand All @@ -19,6 +20,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
ConstantStringType $bound,
?Type $default,
)
{
parent::__construct($bound->getValue());
Expand All @@ -27,6 +29,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

protected function shouldGeneralizeInferredType(): bool
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateFloatType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PHPStan\Type\FloatType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;

/** @api */
final class TemplateFloatType extends FloatType implements TemplateType
Expand All @@ -19,6 +20,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
FloatType $bound,
?Type $default,
)
{
parent::__construct();
Expand All @@ -27,6 +29,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

protected function shouldGeneralizeInferredType(): bool
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateGenericObjectType.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
GenericObjectType $bound,
?Type $default,
)
{
parent::__construct($bound->getClassName(), $bound->getTypes());
Expand All @@ -28,6 +29,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

protected function recreate(string $className, array $types, ?Type $subtractedType): GenericObjectType
Expand All @@ -38,6 +40,7 @@ protected function recreate(string $className, array $types, ?Type $subtractedTy
$this->variance,
$this->name,
$this->getBound(),
$this->default,
);
}

Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateIntegerType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PHPStan\Type\IntegerType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;

/** @api */
final class TemplateIntegerType extends IntegerType implements TemplateType
Expand All @@ -19,6 +20,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
IntegerType $bound,
?Type $default,
)
{
parent::__construct();
Expand All @@ -27,6 +29,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

protected function shouldGeneralizeInferredType(): bool
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateIntersectionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace PHPStan\Type\Generic;

use PHPStan\Type\IntersectionType;
use PHPStan\Type\Type;

/** @api */
final class TemplateIntersectionType extends IntersectionType implements TemplateType
Expand All @@ -17,6 +18,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
IntersectionType $bound,
?Type $default,
)
{
parent::__construct($bound->getTypes());
Expand All @@ -26,6 +28,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

}
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateKeyOfType.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
KeyOfType $bound,
?Type $default,
)
{
parent::__construct($bound->getType());
Expand All @@ -28,6 +29,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

protected function getResult(): Type
Expand All @@ -40,6 +42,7 @@ protected function getResult(): Type
$result,
$this->getVariance(),
$this->getStrategy(),
$this->getDefault(),
);
}

Expand Down
3 changes: 3 additions & 0 deletions src/Type/Generic/TemplateMixedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public function __construct(
TemplateTypeVariance $templateTypeVariance,
string $name,
MixedType $bound,
?Type $default,
)
{
parent::__construct(true);
Expand All @@ -29,6 +30,7 @@ public function __construct(
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
$this->default = $default;
}

public function isSuperTypeOfMixed(MixedType $type): TrinaryLogic
Expand All @@ -53,6 +55,7 @@ public function toStrictMixedType(): TemplateStrictMixedType
$this->variance,
$this->name,
new StrictMixedType(),
$this->default,
);
}

Expand Down
Loading