Skip to content

Commit

Permalink
Support float as template type bound
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Aug 22, 2021
1 parent 9d191f9 commit 4e7d6c1
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 24 deletions.
2 changes: 2 additions & 0 deletions src/Rules/Generics/TemplateTypeCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Rules\ClassNameNodePair;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\BooleanType;
use PHPStan\Type\FloatType;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\Generic\TemplateTypeScope;
Expand Down Expand Up @@ -111,6 +112,7 @@ public function check(
$boundClass === MixedType::class
|| $boundClass === StringType::class
|| $boundClass === IntegerType::class
|| $boundClass === FloatType::class
|| $boundClass === BooleanType::class
|| $boundClass === ObjectWithoutClassType::class
|| $boundClass === ObjectType::class
Expand Down
54 changes: 54 additions & 0 deletions src/Type/Generic/TemplateFloatType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Generic;

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

/** @api */
final class TemplateFloatType extends FloatType implements TemplateType
{

/** @use TemplateTypeTrait<FloatType> */
use TemplateTypeTrait;
use UndecidedComparisonCompoundTypeTrait;

public function __construct(
TemplateTypeScope $scope,
TemplateTypeStrategy $templateTypeStrategy,
TemplateTypeVariance $templateTypeVariance,
string $name,
FloatType $bound
)
{
parent::__construct();
$this->scope = $scope;
$this->strategy = $templateTypeStrategy;
$this->variance = $templateTypeVariance;
$this->name = $name;
$this->bound = $bound;
}

public function traverse(callable $cb): Type
{
$newBound = $cb($this->getBound());
if ($this->getBound() !== $newBound && $newBound instanceof FloatType) {
return new self(
$this->scope,
$this->strategy,
$this->variance,
$this->name,
$newBound
);
}

return $this;
}

protected function shouldGeneralizeInferredType(): bool
{
return false;
}

}
5 changes: 5 additions & 0 deletions src/Type/Generic/TemplateTypeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PHPStan\PhpDoc\Tag\TemplateTag;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\FloatType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
Expand Down Expand Up @@ -45,6 +46,10 @@ public static function create(TemplateTypeScope $scope, string $name, ?Type $bou
return new TemplateIntegerType($scope, $strategy, $variance, $name, $bound);
}

if ($bound instanceof FloatType && ($boundClass === FloatType::class || $bound instanceof TemplateType)) {
return new TemplateFloatType($scope, $strategy, $variance, $name, $bound);
}

if ($bound instanceof BooleanType && ($boundClass === BooleanType::class || $bound instanceof TemplateType)) {
return new TemplateBooleanType($scope, $strategy, $variance, $name, $bound);
}
Expand Down
15 changes: 15 additions & 0 deletions tests/PHPStan/Analyser/data/generics.php
Original file line number Diff line number Diff line change
Expand Up @@ -1422,3 +1422,18 @@ function (bool $b): void {
assertType('false', boolBound(false));
assertType('bool', boolBound($b));
};

/**
* @template T of float
* @param T $f
* @return T
*/
function floatBound(float $f): float
{
return $f;
}

function (float $f): void {
assertType('1.0', floatBound(1.0));
assertType('float', floatBound($f));
};
8 changes: 0 additions & 8 deletions tests/PHPStan/Rules/Generics/ClassTemplateTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ public function testRule(): void
'PHPDoc tag @template T for class ClassTemplateType\Bar has invalid bound type ClassTemplateType\Zazzzu.',
16,
],
[
'PHPDoc tag @template T for class ClassTemplateType\Baz with bound type float is not supported.',
24,
],
[
'Class ClassTemplateType\Baz referenced with incorrect case: ClassTemplateType\baz.',
32,
Expand All @@ -69,10 +65,6 @@ public function testRule(): void
'PHPDoc tag @template T for anonymous class has invalid bound type ClassTemplateType\Zazzzu.',
63,
],
[
'PHPDoc tag @template T for anonymous class with bound type float is not supported.',
68,
],
[
'Class ClassTemplateType\Baz referenced with incorrect case: ClassTemplateType\baz.',
73,
Expand Down
8 changes: 4 additions & 4 deletions tests/PHPStan/Rules/Generics/FunctionTemplateTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ public function testRule(): void
'PHPDoc tag @template T for function FunctionTemplateType\bar() has invalid bound type FunctionTemplateType\Zazzzu.',
16,
],
[
'PHPDoc tag @template T for function FunctionTemplateType\baz() with bound type float is not supported.',
24,
],
[
'PHPDoc tag @template for function FunctionTemplateType\lorem() cannot have existing type alias TypeAlias as its name.',
32,
],
[
'PHPDoc tag @template T for function FunctionTemplateType\resourceBound() with bound type resource is not supported.',
50,
],
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ public function testRule(): void
'PHPDoc tag @template T for interface InterfaceTemplateType\Bar has invalid bound type InterfaceTemplateType\Zazzzu.',
16,
],
[
'PHPDoc tag @template T for interface InterfaceTemplateType\Baz with bound type float is not supported.',
24,
],
[
'PHPDoc tag @template for interface InterfaceTemplateType\Lorem cannot have existing type alias TypeAlias as its name.',
33,
Expand Down
4 changes: 0 additions & 4 deletions tests/PHPStan/Rules/Generics/MethodTemplateTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ public function testRule(): void
'PHPDoc tag @template T for method MethodTemplateType\Bar::doFoo() shadows @template T of Exception for class MethodTemplateType\Bar.',
37,
],
[
'PHPDoc tag @template T for method MethodTemplateType\Baz::doFoo() with bound type float is not supported.',
50,
],
[
'PHPDoc tag @template for method MethodTemplateType\Lorem::doFoo() cannot have existing type alias TypeAlias as its name.',
66,
Expand Down
4 changes: 0 additions & 4 deletions tests/PHPStan/Rules/Generics/TraitTemplateTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ public function testRule(): void
'PHPDoc tag @template T for trait TraitTemplateType\Bar has invalid bound type TraitTemplateType\Zazzzu.',
16,
],
[
'PHPDoc tag @template T for trait TraitTemplateType\Baz with bound type float is not supported.',
24,
],
[
'PHPDoc tag @template for trait TraitTemplateType\Lorem cannot have existing type alias TypeAlias as its name.',
33,
Expand Down
12 changes: 12 additions & 0 deletions tests/PHPStan/Rules/Generics/data/function-template.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,15 @@ function ipsum()
{

}

/** @template T of float */
function dolor()
{

}

/** @template T of resource */
function resourceBound()
{

}

0 comments on commit 4e7d6c1

Please sign in to comment.