Skip to content

Commit 5d59d11

Browse files
committed
Merge branch '1.12.x' into 2.0.x
2 parents a883c66 + ce3ffbd commit 5d59d11

File tree

89 files changed

+903
-80
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+903
-80
lines changed

resources/functionMap.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12606,7 +12606,7 @@
1260612606
'timezone_version_get' => ['string'],
1260712607
'tmpfile' => ['__benevolent<resource|false>'],
1260812608
'token_get_all' => ['list<string|array{0:int,1:string,2:int}>', 'source'=>'string', 'flags='=>'int'],
12609-
'token_name' => ['non-empty-string', 'type'=>'int'],
12609+
'token_name' => ['non-falsy-string', 'type'=>'int'],
1261012610
'TokyoTyrant::__construct' => ['void', 'host='=>'string', 'port='=>'int', 'options='=>'array'],
1261112611
'TokyoTyrant::add' => ['int|float', 'key'=>'string', 'increment'=>'float', 'type='=>'int'],
1261212612
'TokyoTyrant::connect' => ['TokyoTyrant', 'host'=>'string', 'port='=>'int', 'options='=>'array'],

resources/functionMap_php80delta.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
'PhpToken::tokenize' => ['list<PhpToken>', 'code'=>'string', 'flags='=>'int'],
9696
'PhpToken::is' => ['bool', 'kind'=>'string|int|string[]|int[]'],
9797
'PhpToken::isIgnorable' => ['bool'],
98-
'PhpToken::getTokenName' => ['string'],
98+
'PhpToken::getTokenName' => ['non-falsy-string'],
9999
'preg_match_all' => ['0|positive-int|false', 'pattern'=>'string', 'subject'=>'string', '&w_subpatterns='=>'array', 'flags='=>'int', 'offset='=>'int'],
100100
'proc_get_status' => ['array{command: string, pid: int, running: bool, signaled: bool, stopped: bool, exitcode: int, termsig: int, stopsig: int}', 'process'=>'resource'],
101101
'set_error_handler' => ['?callable', 'callback'=>'null|callable(int,string,string,int):bool', 'error_types='=>'int'],

src/Analyser/MutatingScope.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2536,6 +2536,7 @@ private function createFirstClassCallable(
25362536
$templateTags[$templateType->getName()] = new TemplateTag(
25372537
$templateType->getName(),
25382538
$templateType->getBound(),
2539+
$templateType->getDefault(),
25392540
$templateType->getVariance(),
25402541
);
25412542
}
@@ -5547,7 +5548,7 @@ private function exactInstantiation(New_ $node, string $className): ?Type
55475548
if ($type instanceof TemplateType && !$type->isArgument()) {
55485549
$newType = $resolvedTemplateTypeMap->getType($type->getName());
55495550
if ($newType === null || $newType instanceof ErrorType) {
5550-
return $type->getBound();
5551+
return $type->getDefault() ?? $type->getBound();
55515552
}
55525553

55535554
return TemplateTypeHelper::generalizeInferredTemplateType($type, $newType);

src/Dependency/DependencyResolver.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,17 @@ private function addClassToDependencies(string $className, array &$dependenciesR
525525
}
526526
$dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass);
527527
}
528+
529+
$default = $templateTag->getDefault();
530+
if ($default === null) {
531+
continue;
532+
}
533+
foreach ($default->getReferencedClasses() as $referencedClass) {
534+
if (!$this->reflectionProvider->hasClass($referencedClass)) {
535+
continue;
536+
}
537+
$dependenciesReflections[] = $this->reflectionProvider->getClass($referencedClass);
538+
}
528539
}
529540

530541
foreach ($classReflection->getPropertyTags() as $propertyTag) {

src/Parser/ArrowFunctionArgVisitor.php

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,28 @@ final class ArrowFunctionArgVisitor extends NodeVisitorAbstract
1313

1414
public function enterNode(Node $node): ?Node
1515
{
16-
if ($node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Expr\ArrowFunction && !$node->isFirstClassCallable()) {
17-
$args = $node->getArgs();
16+
if (!$node instanceof Node\Expr\FuncCall) {
17+
return null;
18+
}
19+
20+
if ($node->isFirstClassCallable()) {
21+
return null;
22+
}
1823

19-
if (count($args) > 0) {
20-
$node->name->setAttribute(self::ATTRIBUTE_NAME, $args);
21-
}
24+
if ($node->name instanceof Node\Expr\Assign && $node->name->expr instanceof Node\Expr\ArrowFunction) {
25+
$arrow = $node->name->expr;
26+
} elseif ($node->name instanceof Node\Expr\ArrowFunction) {
27+
$arrow = $node->name;
28+
} else {
29+
return null;
2230
}
31+
32+
$args = $node->getArgs();
33+
34+
if (count($args) > 0) {
35+
$arrow->setAttribute(self::ATTRIBUTE_NAME, $args);
36+
}
37+
2338
return null;
2439
}
2540

src/Parser/ClosureArgVisitor.php

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,28 @@ final class ClosureArgVisitor extends NodeVisitorAbstract
1313

1414
public function enterNode(Node $node): ?Node
1515
{
16-
if ($node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Expr\Closure && !$node->isFirstClassCallable()) {
17-
$args = $node->getArgs();
16+
if (!$node instanceof Node\Expr\FuncCall) {
17+
return null;
18+
}
19+
20+
if ($node->isFirstClassCallable()) {
21+
return null;
22+
}
1823

19-
if (count($args) > 0) {
20-
$node->name->setAttribute(self::ATTRIBUTE_NAME, $args);
21-
}
24+
if ($node->name instanceof Node\Expr\Assign && $node->name->expr instanceof Node\Expr\Closure) {
25+
$closure = $node->name->expr;
26+
} elseif ($node->name instanceof Node\Expr\Closure) {
27+
$closure = $node->name;
28+
} else {
29+
return null;
2230
}
31+
32+
$args = $node->getArgs();
33+
34+
if (count($args) > 0) {
35+
$closure->setAttribute(self::ATTRIBUTE_NAME, $args);
36+
}
37+
2338
return null;
2439
}
2540

src/PhpDoc/PhpDocNodeResolver.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ public function resolveMethodTags(PhpDocNode $phpDocNode, NameScope $nameScope):
173173
$templateType->bound !== null
174174
? $this->typeNodeResolver->resolve($templateType->bound, $nameScope)
175175
: new MixedType(),
176+
$templateType->default !== null
177+
? $this->typeNodeResolver->resolve($templateType->default, $nameScope)
178+
: null,
176179
TemplateTypeVariance::createInvariant(),
177180
);
178181
}
@@ -324,9 +327,12 @@ public function resolveTemplateTags(PhpDocNode $phpDocNode, NameScope $nameScope
324327
}
325328
}
326329

330+
$nameScopeWithoutCurrent = $nameScope->unsetTemplateType($valueNode->name);
331+
327332
$resolved[$valueNode->name] = new TemplateTag(
328333
$valueNode->name,
329-
$valueNode->bound !== null ? $this->typeNodeResolver->resolve($valueNode->bound, $nameScope->unsetTemplateType($valueNode->name)) : new MixedType(true),
334+
$valueNode->bound !== null ? $this->typeNodeResolver->resolve($valueNode->bound, $nameScopeWithoutCurrent) : new MixedType(true),
335+
$valueNode->default !== null ? $this->typeNodeResolver->resolve($valueNode->default, $nameScopeWithoutCurrent) : null,
330336
$variance,
331337
);
332338
$resolvedPrefix[$valueNode->name] = $prefix;

src/PhpDoc/Tag/TemplateTag.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ final class TemplateTag
1414
/**
1515
* @param non-empty-string $name
1616
*/
17-
public function __construct(private string $name, private Type $bound, private TemplateTypeVariance $variance)
17+
public function __construct(private string $name, private Type $bound, private ?Type $default, private TemplateTypeVariance $variance)
1818
{
1919
}
2020

@@ -31,6 +31,11 @@ public function getBound(): Type
3131
return $this->bound;
3232
}
3333

34+
public function getDefault(): ?Type
35+
{
36+
return $this->default;
37+
}
38+
3439
public function getVariance(): TemplateTypeVariance
3540
{
3641
return $this->variance;

src/PhpDoc/TypeNodeResolver.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,15 @@ static function (string $variance): TemplateTypeVariance {
792792

793793
$classReflection = $this->getReflectionProvider()->getClass($mainTypeClassName);
794794
if ($classReflection->isGeneric()) {
795+
$templateTypes = array_values($classReflection->getTemplateTypeMap()->getTypes());
796+
for ($i = count($genericTypes), $templateTypesCount = count($templateTypes); $i < $templateTypesCount; $i++) {
797+
$templateType = $templateTypes[$i];
798+
if (!$templateType instanceof TemplateType || $templateType->getDefault() === null) {
799+
continue;
800+
}
801+
$genericTypes[] = $templateType->getDefault();
802+
}
803+
795804
if (in_array($mainTypeClassName, [
796805
Traversable::class,
797806
IteratorAggregate::class,
@@ -910,6 +919,9 @@ private function resolveCallableTypeNode(CallableTypeNode $typeNode, NameScope $
910919
$templateType->bound !== null
911920
? $this->resolve($templateType->bound, $nameScope)
912921
: new MixedType(),
922+
$templateType->default !== null
923+
? $this->resolve($templateType->default, $nameScope)
924+
: null,
913925
TemplateTypeVariance::createInvariant(),
914926
);
915927
}

src/Reflection/ClassReflection.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,7 +1432,7 @@ public function typeMapFromList(array $types): TemplateTypeMap
14321432
$map = [];
14331433
$i = 0;
14341434
foreach ($resolvedPhpDoc->getTemplateTags() as $tag) {
1435-
$map[$tag->getName()] = $types[$i] ?? $tag->getBound();
1435+
$map[$tag->getName()] = $types[$i] ?? $tag->getDefault() ?? $tag->getBound();
14361436
$i++;
14371437
}
14381438

@@ -1469,7 +1469,7 @@ public function typeMapToList(TemplateTypeMap $typeMap): array
14691469

14701470
$list = [];
14711471
foreach ($resolvedPhpDoc->getTemplateTags() as $tag) {
1472-
$list[] = $typeMap->getType($tag->getName()) ?? $tag->getBound();
1472+
$list[] = $typeMap->getType($tag->getName()) ?? $tag->getDefault() ?? $tag->getBound();
14731473
}
14741474

14751475
return $list;

src/Rules/Classes/LocalTypeAliasesCheck.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
use PHPStan\Type\VerbosityLevel;
2525
use function array_key_exists;
2626
use function array_merge;
27-
use function implode;
2827
use function in_array;
2928
use function sprintf;
3029

@@ -206,7 +205,7 @@ public function checkInTraitDefinitionContext(ClassReflection $reflection): arra
206205
$reflection->getDisplayName(),
207206
$aliasName,
208207
$name,
209-
implode(', ', $genericTypeNames),
208+
$genericTypeNames,
210209
))
211210
->identifier('missingType.generics')
212211
->build();

src/Rules/Classes/MethodTagCheck.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
use PHPStan\Type\Type;
1717
use PHPStan\Type\VerbosityLevel;
1818
use function array_merge;
19-
use function implode;
2019
use function sprintf;
2120

2221
final class MethodTagCheck
@@ -174,7 +173,7 @@ private function checkMethodTypeInTraitDefinitionContext(ClassReflection $classR
174173
$methodName,
175174
$description,
176175
$innerName,
177-
implode(', ', $genericTypeNames),
176+
$genericTypeNames,
178177
))
179178
->identifier('missingType.generics')
180179
->build();

src/Rules/Classes/MixinCheck.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use PHPStan\Rules\RuleErrorBuilder;
1515
use PHPStan\Type\VerbosityLevel;
1616
use function array_merge;
17-
use function implode;
1817
use function sprintf;
1918

2019
final class MixinCheck
@@ -85,7 +84,7 @@ public function checkInTraitDefinitionContext(ClassReflection $classReflection):
8584
$errors[] = RuleErrorBuilder::message(sprintf(
8685
'PHPDoc tag @mixin contains generic %s but does not specify its types: %s',
8786
$innerName,
88-
implode(', ', $genericTypeNames),
87+
$genericTypeNames,
8988
))
9089
->identifier('missingType.generics')
9190
->build();

src/Rules/Classes/PropertyTagCheck.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use PHPStan\Type\Type;
1919
use PHPStan\Type\VerbosityLevel;
2020
use function array_merge;
21-
use function implode;
2221
use function sprintf;
2322

2423
final class PropertyTagCheck
@@ -155,7 +154,7 @@ private function checkPropertyTypeInTraitDefinitionContext(ClassReflection $clas
155154
$classReflection->getDisplayName(),
156155
$propertyName,
157156
$innerName,
158-
implode(', ', $genericTypeNames),
157+
$genericTypeNames,
159158
))
160159
->identifier('missingType.generics')
161160
->build();

src/Rules/Constants/MissingClassConstantTypehintRule.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use PHPStan\ShouldNotHappenException;
1313
use PHPStan\Type\VerbosityLevel;
1414
use function array_merge;
15-
use function implode;
1615
use function sprintf;
1716

1817
/**
@@ -76,7 +75,7 @@ private function processSingleConstant(ClassReflection $classReflection, string
7675
$constantReflection->getDeclaringClass()->getDisplayName(),
7776
$constantName,
7877
$name,
79-
implode(', ', $genericTypeNames),
78+
$genericTypeNames,
8079
))
8180
->identifier('missingType.generics')
8281
->build();

src/Rules/FunctionCallParametersCheck.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ static function (Type $type, callable $traverse) use (&$returnTemplateTypes): Ty
441441
$type = $type->resolve();
442442
}
443443

444-
if ($type instanceof TemplateType) {
444+
if ($type instanceof TemplateType && $type->getDefault() === null) {
445445
$returnTemplateTypes[$type->getName()] = true;
446446
return $type;
447447
}
@@ -453,7 +453,7 @@ static function (Type $type, callable $traverse) use (&$returnTemplateTypes): Ty
453453
$parameterTemplateTypes = [];
454454
foreach ($originalParametersAcceptor->getParameters() as $parameter) {
455455
TypeTraverser::map($parameter->getType(), static function (Type $type, callable $traverse) use (&$parameterTemplateTypes): Type {
456-
if ($type instanceof TemplateType) {
456+
if ($type instanceof TemplateType && $type->getDefault() === null) {
457457
$parameterTemplateTypes[$type->getName()] = true;
458458
return $type;
459459
}

src/Rules/Functions/MissingFunctionParameterTypehintRule.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use PHPStan\Type\MixedType;
1414
use PHPStan\Type\Type;
1515
use PHPStan\Type\VerbosityLevel;
16-
use function implode;
1716
use function sprintf;
1817

1918
/**
@@ -96,7 +95,7 @@ private function checkFunctionParameter(FunctionReflection $functionReflection,
9695
$functionReflection->getName(),
9796
$parameterMessage,
9897
$name,
99-
implode(', ', $genericTypeNames),
98+
$genericTypeNames,
10099
))
101100
->identifier('missingType.generics')
102101
->build();

src/Rules/Functions/MissingFunctionReturnTypehintRule.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use PHPStan\Rules\RuleErrorBuilder;
1111
use PHPStan\Type\MixedType;
1212
use PHPStan\Type\VerbosityLevel;
13-
use function implode;
1413
use function sprintf;
1514

1615
/**
@@ -58,7 +57,7 @@ public function processNode(Node $node, Scope $scope): array
5857
'Function %s() return type with generic %s does not specify its types: %s',
5958
$functionReflection->getName(),
6059
$name,
61-
implode(', ', $genericTypeNames),
60+
$genericTypeNames,
6261
))
6362
->identifier('missingType.generics')
6463
->build();

src/Rules/Generics/ClassTemplateTypeRule.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ public function processNode(Node $node, Scope $scope): array
4949
sprintf('PHPDoc tag @template for %s cannot have existing type alias %%s as its name.', $displayName),
5050
sprintf('PHPDoc tag @template %%s for %s has invalid bound type %%s.', $displayName),
5151
sprintf('PHPDoc tag @template %%s for %s with bound type %%s is not supported.', $displayName),
52+
sprintf('PHPDoc tag @template %%s for %s has invalid default type %%s.', $displayName),
53+
sprintf('Default type %%s in PHPDoc tag @template %%s for %s is not subtype of bound type %%s.', $displayName),
54+
sprintf('PHPDoc tag @template %%s for %s does not have a default type but follows an optional @template %%s.', $displayName),
5255
);
5356
}
5457

src/Rules/Generics/FunctionTemplateTypeRule.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ public function processNode(Node $node, Scope $scope): array
6060
sprintf('PHPDoc tag @template for function %s() cannot have existing type alias %%s as its name.', $escapedFunctionName),
6161
sprintf('PHPDoc tag @template %%s for function %s() has invalid bound type %%s.', $escapedFunctionName),
6262
sprintf('PHPDoc tag @template %%s for function %s() with bound type %%s is not supported.', $escapedFunctionName),
63+
sprintf('PHPDoc tag @template %%s for function %s() has invalid default type %%s.', $escapedFunctionName),
64+
sprintf('Default type %%s in PHPDoc tag @template %%s for function %s() is not subtype of bound type %%s.', $escapedFunctionName),
65+
sprintf('PHPDoc tag @template %%s for function %s() does not have a default type but follows an optional @template %%s.', $escapedFunctionName),
6366
);
6467
}
6568

0 commit comments

Comments
 (0)