Skip to content

Commit 387ebd5

Browse files
committed
Some useful advanced PHPDoc types
1 parent 9850ea7 commit 387ebd5

File tree

3 files changed

+72
-0
lines changed

3 files changed

+72
-0
lines changed

src/PhpDoc/TypeNodeResolver.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco
198198
case 'class-string':
199199
case 'interface-string':
200200
case 'trait-string':
201+
case 'enum-string':
201202
return new ClassStringType();
202203

203204
case 'callable-string':
@@ -215,6 +216,18 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco
215216

216217
return new UnionType([new IntegerType(), new FloatType(), new StringType(), new BooleanType()]);
217218

219+
case 'empty-scalar':
220+
return TypeCombinator::intersect(
221+
new UnionType([new IntegerType(), new FloatType(), new StringType(), new BooleanType()]),
222+
StaticTypeFactory::falsey(),
223+
);
224+
225+
case 'non-empty-scalar':
226+
return TypeCombinator::remove(
227+
new UnionType([new IntegerType(), new FloatType(), new StringType(), new BooleanType()]),
228+
StaticTypeFactory::falsey(),
229+
);
230+
218231
case 'number':
219232
$type = $this->tryResolvePseudoTypeClassType($typeNode, $nameScope);
220233

@@ -260,6 +273,13 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco
260273
new AccessoryNonFalsyStringType(),
261274
]);
262275

276+
case 'non-empty-literal-string':
277+
return new IntersectionType([
278+
new StringType(),
279+
new AccessoryNonEmptyStringType(),
280+
new AccessoryLiteralStringType(),
281+
]);
282+
263283
case 'bool':
264284
return new BooleanType();
265285

@@ -307,6 +327,7 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco
307327
return new IterableType(new MixedType(), new MixedType());
308328

309329
case 'callable':
330+
case 'pure-callable':
310331
return new CallableType();
311332

312333
case 'resource':
@@ -318,9 +339,15 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco
318339

319340
return new ResourceType();
320341

342+
case 'closed-resource':
343+
return new ResourceType();
344+
321345
case 'mixed':
322346
return new MixedType(true);
323347

348+
case 'non-empty-mixed':
349+
return new MixedType(true, StaticTypeFactory::falsey());
350+
324351
case 'void':
325352
return new VoidType();
326353

@@ -330,6 +357,9 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco
330357
case 'callable-object':
331358
return new IntersectionType([new ObjectWithoutClassType(), new CallableType()]);
332359

360+
case 'callable-array':
361+
return new IntersectionType([new ArrayType(new MixedType(), new MixedType()), new CallableType()]);
362+
333363
case 'never':
334364
case 'noreturn':
335365
$type = $this->tryResolvePseudoTypeClassType($typeNode, $nameScope);

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,7 @@ public function dataFileAsserts(): iterable
12201220
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-8609.php');
12211221
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/PhpDoc/data/bug-8609-function.php');
12221222
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9131.php');
1223+
yield from $this->gatherAssertTypes(__DIR__ . '/data/more-types.php');
12231224
}
12241225

12251226
/**
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace MoreTypes;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
10+
/**
11+
* @param pure-callable $pureCallable
12+
* @param callable-array $callableArray
13+
* @param closed-resource $closedResource
14+
* @param enum-string $enumString
15+
* @param non-empty-literal-string $nonEmptyLiteralString
16+
* @param non-empty-scalar $nonEmptyScalar
17+
* @param empty-scalar $emptyScalar
18+
* @param non-empty-mixed $nonEmptyMixed
19+
*/
20+
public function doFoo(
21+
$pureCallable,
22+
$callableArray,
23+
$closedResource,
24+
$enumString,
25+
$nonEmptyLiteralString,
26+
$nonEmptyScalar,
27+
$emptyScalar,
28+
$nonEmptyMixed
29+
): void
30+
{
31+
assertType('callable(): mixed', $pureCallable);
32+
assertType('array&callable(): mixed', $callableArray);
33+
assertType('resource', $closedResource);
34+
assertType('class-string', $enumString);
35+
assertType('literal-string&non-empty-string', $nonEmptyLiteralString);
36+
assertType('float|int<min, -1>|int<1, max>|non-falsy-string|true', $nonEmptyScalar);
37+
assertType("0|0.0|''|'0'|false", $emptyScalar);
38+
assertType("mixed~0|0.0|''|'0'|array{}|false|null", $nonEmptyMixed);
39+
}
40+
41+
}

0 commit comments

Comments
 (0)