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
2 changes: 2 additions & 0 deletions src/Type/ParserNodeTypeToPHPStanType.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ public static function resolve($type, ?ClassReflection $classReflection): Type
return new VoidType();
} elseif ($type === 'object') {
return new ObjectWithoutClassType();
} elseif ($type === 'true') {
return new ConstantBooleanType(true);
} elseif ($type === 'false') {
return new ConstantBooleanType(false);
} elseif ($type === 'null') {
Expand Down
5 changes: 5 additions & 0 deletions src/Type/TypehintHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ private static function getTypeObjectFromTypehint(string $typeString, ?string $s
return new BooleanType();
case 'false':
return new ConstantBooleanType(false);
case 'true':
return new ConstantBooleanType(true);
case 'string':
return new StringType();
case 'float':
Expand Down Expand Up @@ -118,6 +120,9 @@ public static function decideTypeFromReflection(
if (str_ends_with(strtolower($reflectionTypeString), '\\mixed')) {
$reflectionTypeString = 'mixed';
}
if (str_ends_with(strtolower($reflectionTypeString), '\\true')) {
$reflectionTypeString = 'true';
}
if (str_ends_with(strtolower($reflectionTypeString), '\\false')) {
$reflectionTypeString = 'false';
}
Expand Down
4 changes: 4 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,10 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7788.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7809.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/composer-non-empty-array-after-unset.php');

if (PHP_VERSION_ID >= 80200) {
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Methods/data/true-typehint.php');
}
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Arrays/data/bug-6000.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/prestashop-breakdowns-empty-array.php');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,25 @@ public function testIntersectionTypes(int $phpVersion, array $errors): void
$this->analyse([__DIR__ . '/data/intersection-types.php'], $errors);
}

public function dataTrueTypes(): array
{
return [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initially I had the idea to make the new type only available on php 8.2+, but it seems atm we cannot do it in a version dependent way.

maybe this would even be more like a linter task.. leave it like this for now, as I realized thats the way we implemented such types in the past

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allegedly this is gonna be solved in PHP-Parser 5.0 which is gonna make a thick line between Name and Identifier dependent on PHP version.

[
80200,
[],
],
];
}

/**
* @dataProvider dataTrueTypes
* @param mixed[] $errors
*/
public function testTrueTypehint(int $phpVersion, array $errors): void
{
$this->phpVersionId = $phpVersion;

$this->analyse([__DIR__ . '/data/true-typehint.php'], $errors);
}

}
8 changes: 8 additions & 0 deletions tests/PHPStan/Rules/Functions/data/true-typehint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php // lint >= 8.2

namespace NativeTrueType;

function alwaysTrue(): true
{
return true;
}
18 changes: 18 additions & 0 deletions tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -291,4 +291,22 @@ public function testEnums(): void
]);
}

public function dataTrueTypes(): array
{
return [
[80200, []],
];
}

/**
* @dataProvider dataTrueTypes
* @param mixed[] $errors
*/
public function testTrueTypehint(int $phpVersion, array $errors): void
{
$this->phpVersionId = $phpVersion;

$this->analyse([__DIR__ . '/data/true-typehint.php'], $errors);
}

}
44 changes: 44 additions & 0 deletions tests/PHPStan/Rules/Methods/data/true-typehint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php // lint >= 8.2

namespace NativeTrueType;

use function PHPStan\Testing\assertType;

class Truthy {
public true $truthy = true;

public function foo(true $v): true {
assertType('true', $v);
}

function trueUnion(true|null $trueUnion): void
{
assertType('true|null', $trueUnion);

if (is_null($trueUnion)) {
assertType('null', $trueUnion);
return;
}

if (is_bool($trueUnion)) {
assertType('true', $trueUnion);
return;
}

assertType('*NEVER*', $trueUnion);
}

function trueUnionReturn(): true|null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are the other two methods tested? I'd expect more assertType calls here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

{
if (rand(1, 0)) {
return true;
}
return null;
}
}

function foo(Truthy $truthy) {
assertType('true', $truthy->truthy);
assertType('true', $truthy->foo(true));
assertType('true|null', $truthy->trueUnionReturn());
}