Skip to content

Commit d5fdc37

Browse files
committed
Combine types into an ArrayShapeUnsealedTypeNode
1 parent 44f302c commit d5fdc37

File tree

5 files changed

+170
-77
lines changed

5 files changed

+170
-77
lines changed

src/Ast/Type/ArrayShapeNode.php

+5-19
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,8 @@ class ArrayShapeNode implements TypeNode
2222
/** @var self::KIND_* */
2323
public $kind;
2424

25-
/** @var TypeNode|null */
26-
public $extraKeyType;
27-
28-
/** @var TypeNode|null */
29-
public $extraValueType;
25+
/** @var ArrayShapeUnsealedTypeNode|null */
26+
public $unsealedType;
3027

3128
/**
3229
* @param ArrayShapeItemNode[] $items
@@ -36,15 +33,13 @@ public function __construct(
3633
array $items,
3734
bool $sealed = true,
3835
string $kind = self::KIND_ARRAY,
39-
?TypeNode $extraKeyType = null,
40-
?TypeNode $extraValueType = null
36+
?ArrayShapeUnsealedTypeNode $unsealedType = null
4137
)
4238
{
4339
$this->items = $items;
4440
$this->sealed = $sealed;
4541
$this->kind = $kind;
46-
$this->extraKeyType = $extraKeyType;
47-
$this->extraValueType = $extraValueType;
42+
$this->unsealedType = $unsealedType;
4843
}
4944

5045

@@ -53,16 +48,7 @@ public function __toString(): string
5348
$items = $this->items;
5449

5550
if (! $this->sealed) {
56-
$item = '...';
57-
if ($this->extraValueType !== null) {
58-
$extraTypes = [];
59-
if ($this->extraKeyType !== null) {
60-
$extraTypes[] = (string) $this->extraKeyType;
61-
}
62-
$extraTypes[] = (string) $this->extraValueType;
63-
$item .= '<' . implode(', ', $extraTypes) . '>';
64-
}
65-
$items[] = $item;
51+
$items[] = '...' . $this->unsealedType;
6652
}
6753

6854
return $this->kind . '{' . implode(', ', $items) . '}';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\PhpDocParser\Ast\Type;
4+
5+
use PHPStan\PhpDocParser\Ast\NodeAttributes;
6+
use function sprintf;
7+
8+
class ArrayShapeUnsealedTypeNode implements TypeNode
9+
{
10+
11+
use NodeAttributes;
12+
13+
/** @var TypeNode */
14+
public $valueType;
15+
16+
/** @var TypeNode|null */
17+
public $keyType;
18+
19+
public function __construct(TypeNode $valueType, ?TypeNode $keyType)
20+
{
21+
$this->valueType = $valueType;
22+
$this->keyType = $keyType;
23+
}
24+
25+
public function __toString(): string
26+
{
27+
if ($this->keyType !== null) {
28+
return sprintf('<%s, %s>', $this->keyType, $this->valueType);
29+
}
30+
return sprintf('<%s>', $this->valueType);
31+
}
32+
33+
}

src/Parser/TypeParser.php

+63-18
Original file line numberDiff line numberDiff line change
@@ -848,8 +848,7 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
848848

849849
$items = [];
850850
$sealed = true;
851-
$extraKeyType = null;
852-
$extraValueType = null;
851+
$unsealedType = null;
853852

854853
do {
855854
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
@@ -862,23 +861,12 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
862861
$sealed = false;
863862

864863
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
865-
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
866-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
867-
868-
$extraValueType = $this->parse($tokens);
869-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
870-
864+
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
871865
if ($kind === Ast\Type\ArrayShapeNode::KIND_ARRAY) {
872-
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
873-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
874-
875-
$extraKeyType = $extraValueType;
876-
$extraValueType = $this->parse($tokens);
877-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
878-
}
866+
$unsealedType = $this->parseArrayShapeUnsealedType($tokens);
867+
} else {
868+
$unsealedType = $this->parseListShapeUnsealedType($tokens);
879869
}
880-
881-
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
882870
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
883871
}
884872

@@ -894,7 +882,7 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
894882
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
895883
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
896884

897-
return new Ast\Type\ArrayShapeNode($items, $sealed, $kind, $extraKeyType, $extraValueType);
885+
return new Ast\Type\ArrayShapeNode($items, $sealed, $kind, $unsealedType);
898886
}
899887

900888

@@ -973,6 +961,63 @@ private function parseArrayShapeKey(TokenIterator $tokens)
973961
);
974962
}
975963

964+
/**
965+
* @phpstan-impure
966+
*/
967+
private function parseArrayShapeUnsealedType(TokenIterator $tokens): Ast\Type\ArrayShapeUnsealedTypeNode
968+
{
969+
$startLine = $tokens->currentTokenLine();
970+
$startIndex = $tokens->currentTokenIndex();
971+
972+
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
973+
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
974+
975+
$valueType = $this->parse($tokens);
976+
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
977+
978+
$keyType = null;
979+
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
980+
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
981+
982+
$keyType = $valueType;
983+
$valueType = $this->parse($tokens);
984+
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
985+
}
986+
987+
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
988+
989+
return $this->enrichWithAttributes(
990+
$tokens,
991+
new Ast\Type\ArrayShapeUnsealedTypeNode($valueType, $keyType),
992+
$startLine,
993+
$startIndex
994+
);
995+
}
996+
997+
/**
998+
* @phpstan-impure
999+
*/
1000+
private function parseListShapeUnsealedType(TokenIterator $tokens): Ast\Type\ArrayShapeUnsealedTypeNode
1001+
{
1002+
$startLine = $tokens->currentTokenLine();
1003+
$startIndex = $tokens->currentTokenIndex();
1004+
1005+
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
1006+
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
1007+
1008+
$valueType = $this->parse($tokens);
1009+
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
1010+
1011+
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
1012+
1013+
return $this->enrichWithAttributes(
1014+
$tokens,
1015+
new Ast\Type\ArrayShapeUnsealedTypeNode($valueType, null),
1016+
$startLine,
1017+
$startIndex
1018+
);
1019+
}
1020+
9761021
/**
9771022
* @phpstan-impure
9781023
*/

src/Printer/Printer.php

+8-10
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
4444
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode;
4545
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
46+
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeUnsealedTypeNode;
4647
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
4748
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
4849
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
@@ -366,16 +367,7 @@ private function printType(TypeNode $node): string
366367
}, $node->items);
367368

368369
if (! $node->sealed) {
369-
$item = '...';
370-
if ($node->extraValueType !== null) {
371-
$extraTypes = [];
372-
if ($node->extraKeyType !== null) {
373-
$extraTypes[] = $this->printType($node->extraKeyType);
374-
}
375-
$extraTypes[] = $this->printType($node->extraValueType);
376-
$item .= '<' . implode(', ', $extraTypes) . '>';
377-
}
378-
$items[] = $item;
370+
$items[] = '...' . ($node->unsealedType === null ? '' : $this->printType($node->unsealedType));
379371
}
380372

381373
return $node->kind . '{' . implode(', ', $items) . '}';
@@ -392,6 +384,12 @@ private function printType(TypeNode $node): string
392384

393385
return $this->printType($node->valueType);
394386
}
387+
if ($node instanceof ArrayShapeUnsealedTypeNode) {
388+
if ($node->keyType !== null) {
389+
return sprintf('<%s, %s>', $this->printType($node->keyType), $this->printType($node->valueType));
390+
}
391+
return sprintf('<%s>', $this->printType($node->valueType));
392+
}
395393
if ($node instanceof ArrayTypeNode) {
396394
return $this->printOffsetAccessType($node->type) . '[]';
397395
}

0 commit comments

Comments
 (0)