Skip to content

Commit 4e7d6c1

Browse files
committed
Support float as template type bound
1 parent 9d191f9 commit 4e7d6c1

10 files changed

+92
-24
lines changed

src/Rules/Generics/TemplateTypeCheck.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\Rules\ClassNameNodePair;
99
use PHPStan\Rules\RuleErrorBuilder;
1010
use PHPStan\Type\BooleanType;
11+
use PHPStan\Type\FloatType;
1112
use PHPStan\Type\Generic\GenericObjectType;
1213
use PHPStan\Type\Generic\TemplateType;
1314
use PHPStan\Type\Generic\TemplateTypeScope;
@@ -111,6 +112,7 @@ public function check(
111112
$boundClass === MixedType::class
112113
|| $boundClass === StringType::class
113114
|| $boundClass === IntegerType::class
115+
|| $boundClass === FloatType::class
114116
|| $boundClass === BooleanType::class
115117
|| $boundClass === ObjectWithoutClassType::class
116118
|| $boundClass === ObjectType::class
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Generic;
4+
5+
use PHPStan\Type\FloatType;
6+
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
7+
use PHPStan\Type\Type;
8+
9+
/** @api */
10+
final class TemplateFloatType extends FloatType implements TemplateType
11+
{
12+
13+
/** @use TemplateTypeTrait<FloatType> */
14+
use TemplateTypeTrait;
15+
use UndecidedComparisonCompoundTypeTrait;
16+
17+
public function __construct(
18+
TemplateTypeScope $scope,
19+
TemplateTypeStrategy $templateTypeStrategy,
20+
TemplateTypeVariance $templateTypeVariance,
21+
string $name,
22+
FloatType $bound
23+
)
24+
{
25+
parent::__construct();
26+
$this->scope = $scope;
27+
$this->strategy = $templateTypeStrategy;
28+
$this->variance = $templateTypeVariance;
29+
$this->name = $name;
30+
$this->bound = $bound;
31+
}
32+
33+
public function traverse(callable $cb): Type
34+
{
35+
$newBound = $cb($this->getBound());
36+
if ($this->getBound() !== $newBound && $newBound instanceof FloatType) {
37+
return new self(
38+
$this->scope,
39+
$this->strategy,
40+
$this->variance,
41+
$this->name,
42+
$newBound
43+
);
44+
}
45+
46+
return $this;
47+
}
48+
49+
protected function shouldGeneralizeInferredType(): bool
50+
{
51+
return false;
52+
}
53+
54+
}

src/Type/Generic/TemplateTypeFactory.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PHPStan\PhpDoc\Tag\TemplateTag;
66
use PHPStan\Type\BenevolentUnionType;
77
use PHPStan\Type\BooleanType;
8+
use PHPStan\Type\FloatType;
89
use PHPStan\Type\IntegerType;
910
use PHPStan\Type\MixedType;
1011
use PHPStan\Type\ObjectType;
@@ -45,6 +46,10 @@ public static function create(TemplateTypeScope $scope, string $name, ?Type $bou
4546
return new TemplateIntegerType($scope, $strategy, $variance, $name, $bound);
4647
}
4748

49+
if ($bound instanceof FloatType && ($boundClass === FloatType::class || $bound instanceof TemplateType)) {
50+
return new TemplateFloatType($scope, $strategy, $variance, $name, $bound);
51+
}
52+
4853
if ($bound instanceof BooleanType && ($boundClass === BooleanType::class || $bound instanceof TemplateType)) {
4954
return new TemplateBooleanType($scope, $strategy, $variance, $name, $bound);
5055
}

tests/PHPStan/Analyser/data/generics.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,3 +1422,18 @@ function (bool $b): void {
14221422
assertType('false', boolBound(false));
14231423
assertType('bool', boolBound($b));
14241424
};
1425+
1426+
/**
1427+
* @template T of float
1428+
* @param T $f
1429+
* @return T
1430+
*/
1431+
function floatBound(float $f): float
1432+
{
1433+
return $f;
1434+
}
1435+
1436+
function (float $f): void {
1437+
assertType('1.0', floatBound(1.0));
1438+
assertType('float', floatBound($f));
1439+
};

tests/PHPStan/Rules/Generics/ClassTemplateTypeRuleTest.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,6 @@ public function testRule(): void
4141
'PHPDoc tag @template T for class ClassTemplateType\Bar has invalid bound type ClassTemplateType\Zazzzu.',
4242
16,
4343
],
44-
[
45-
'PHPDoc tag @template T for class ClassTemplateType\Baz with bound type float is not supported.',
46-
24,
47-
],
4844
[
4945
'Class ClassTemplateType\Baz referenced with incorrect case: ClassTemplateType\baz.',
5046
32,
@@ -69,10 +65,6 @@ public function testRule(): void
6965
'PHPDoc tag @template T for anonymous class has invalid bound type ClassTemplateType\Zazzzu.',
7066
63,
7167
],
72-
[
73-
'PHPDoc tag @template T for anonymous class with bound type float is not supported.',
74-
68,
75-
],
7668
[
7769
'Class ClassTemplateType\Baz referenced with incorrect case: ClassTemplateType\baz.',
7870
73,

tests/PHPStan/Rules/Generics/FunctionTemplateTypeRuleTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ public function testRule(): void
3535
'PHPDoc tag @template T for function FunctionTemplateType\bar() has invalid bound type FunctionTemplateType\Zazzzu.',
3636
16,
3737
],
38-
[
39-
'PHPDoc tag @template T for function FunctionTemplateType\baz() with bound type float is not supported.',
40-
24,
41-
],
4238
[
4339
'PHPDoc tag @template for function FunctionTemplateType\lorem() cannot have existing type alias TypeAlias as its name.',
4440
32,
4541
],
42+
[
43+
'PHPDoc tag @template T for function FunctionTemplateType\resourceBound() with bound type resource is not supported.',
44+
50,
45+
],
4646
]);
4747
}
4848

tests/PHPStan/Rules/Generics/InterfaceTemplateTypeRuleTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ public function testRule(): void
3737
'PHPDoc tag @template T for interface InterfaceTemplateType\Bar has invalid bound type InterfaceTemplateType\Zazzzu.',
3838
16,
3939
],
40-
[
41-
'PHPDoc tag @template T for interface InterfaceTemplateType\Baz with bound type float is not supported.',
42-
24,
43-
],
4440
[
4541
'PHPDoc tag @template for interface InterfaceTemplateType\Lorem cannot have existing type alias TypeAlias as its name.',
4642
33,

tests/PHPStan/Rules/Generics/MethodTemplateTypeRuleTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,6 @@ public function testRule(): void
4141
'PHPDoc tag @template T for method MethodTemplateType\Bar::doFoo() shadows @template T of Exception for class MethodTemplateType\Bar.',
4242
37,
4343
],
44-
[
45-
'PHPDoc tag @template T for method MethodTemplateType\Baz::doFoo() with bound type float is not supported.',
46-
50,
47-
],
4844
[
4945
'PHPDoc tag @template for method MethodTemplateType\Lorem::doFoo() cannot have existing type alias TypeAlias as its name.',
5046
66,

tests/PHPStan/Rules/Generics/TraitTemplateTypeRuleTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ public function testRule(): void
3737
'PHPDoc tag @template T for trait TraitTemplateType\Bar has invalid bound type TraitTemplateType\Zazzzu.',
3838
16,
3939
],
40-
[
41-
'PHPDoc tag @template T for trait TraitTemplateType\Baz with bound type float is not supported.',
42-
24,
43-
],
4440
[
4541
'PHPDoc tag @template for trait TraitTemplateType\Lorem cannot have existing type alias TypeAlias as its name.',
4642
33,

tests/PHPStan/Rules/Generics/data/function-template.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,15 @@ function ipsum()
3939
{
4040

4141
}
42+
43+
/** @template T of float */
44+
function dolor()
45+
{
46+
47+
}
48+
49+
/** @template T of resource */
50+
function resourceBound()
51+
{
52+
53+
}

0 commit comments

Comments
 (0)