Skip to content

Commit 44f302c

Browse files
committed
Use separate extra key/value types instead of a generic type
1 parent edcdee8 commit 44f302c

File tree

4 files changed

+138
-170
lines changed

4 files changed

+138
-170
lines changed

src/Ast/Type/ArrayShapeNode.php

+16-12
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@
22

33
namespace PHPStan\PhpDocParser\Ast\Type;
44

5-
use InvalidArgumentException;
65
use PHPStan\PhpDocParser\Ast\NodeAttributes;
76
use function implode;
8-
use function strlen;
9-
use function substr;
107

118
class ArrayShapeNode implements TypeNode
129
{
@@ -25,8 +22,11 @@ class ArrayShapeNode implements TypeNode
2522
/** @var self::KIND_* */
2623
public $kind;
2724

28-
/** @var GenericTypeNode|null */
29-
public $extraItemType;
25+
/** @var TypeNode|null */
26+
public $extraKeyType;
27+
28+
/** @var TypeNode|null */
29+
public $extraValueType;
3030

3131
/**
3232
* @param ArrayShapeItemNode[] $items
@@ -36,16 +36,15 @@ public function __construct(
3636
array $items,
3737
bool $sealed = true,
3838
string $kind = self::KIND_ARRAY,
39-
?GenericTypeNode $extraItemType = null
39+
?TypeNode $extraKeyType = null,
40+
?TypeNode $extraValueType = null
4041
)
4142
{
4243
$this->items = $items;
4344
$this->sealed = $sealed;
4445
$this->kind = $kind;
45-
$this->extraItemType = $extraItemType;
46-
if ($sealed && $extraItemType !== null) {
47-
throw new InvalidArgumentException('An extra item type may only be set for an unsealed array shape');
48-
}
46+
$this->extraKeyType = $extraKeyType;
47+
$this->extraValueType = $extraValueType;
4948
}
5049

5150

@@ -55,8 +54,13 @@ public function __toString(): string
5554

5655
if (! $this->sealed) {
5756
$item = '...';
58-
if ($this->extraItemType !== null) {
59-
$item .= substr((string) $this->extraItemType, strlen((string) $this->extraItemType->type));
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) . '>';
6064
}
6165
$items[] = $item;
6266
}

src/Parser/TypeParser.php

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

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

853854
do {
854855
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
@@ -859,19 +860,28 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
859860

860861
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) {
861862
$sealed = false;
863+
862864
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
863-
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
864-
$extraItemType = $this->parseGeneric(
865-
$tokens,
866-
$this->enrichWithAttributes(
867-
$tokens,
868-
new Ast\Type\IdentifierTypeNode($kind),
869-
$tokens->currentTokenLine(),
870-
$tokens->currentTokenIndex()
871-
)
872-
);
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+
871+
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+
}
879+
}
880+
881+
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
873882
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
874883
}
884+
875885
$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA);
876886
break;
877887
}
@@ -884,7 +894,7 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
884894
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
885895
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
886896

887-
return new Ast\Type\ArrayShapeNode($items, $sealed, $kind, $extraItemType);
897+
return new Ast\Type\ArrayShapeNode($items, $sealed, $kind, $extraKeyType, $extraValueType);
888898
}
889899

890900

src/Printer/Printer.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@
7474
use function sprintf;
7575
use function strlen;
7676
use function strpos;
77-
use function substr;
7877
use function trim;
7978
use const PREG_SET_ORDER;
8079

@@ -368,8 +367,13 @@ private function printType(TypeNode $node): string
368367

369368
if (! $node->sealed) {
370369
$item = '...';
371-
if ($node->extraItemType !== null) {
372-
$item .= substr($this->printType($node->extraItemType), strlen((string) $node->extraItemType->type));
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) . '>';
373377
}
374378
$items[] = $item;
375379
}

0 commit comments

Comments
 (0)