Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 950bddf

Browse files
jrmajorondrejmirtes
authored andcommitted
Support unsealed array shapes
1 parent 6ff970a commit 950bddf

File tree

3 files changed

+94
-12
lines changed

3 files changed

+94
-12
lines changed

‎src/Ast/Type/ArrayShapeNode.php‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,25 @@ class ArrayShapeNode implements TypeNode
1313
/** @var ArrayShapeItemNode[] */
1414
public $items;
1515

16-
public function __construct(array $items)
16+
/** @var bool */
17+
public $sealed;
18+
19+
public function __construct(array $items, bool $sealed = true)
1720
{
1821
$this->items = $items;
22+
$this->sealed = $sealed;
1923
}
2024

2125

2226
public function __toString(): string
2327
{
24-
return 'array{' . implode(', ', $this->items) . '}';
28+
$items = $this->items;
29+
30+
if ($this->sealed) {
31+
$items[] = '...';
32+
}
33+
34+
return 'array{' . implode(', ', $items) . '}';
2535
}
2636

2737
}

‎src/Parser/TypeParser.php‎

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -503,29 +503,32 @@ private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\Typ
503503
private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast\Type\ArrayShapeNode
504504
{
505505
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);
506-
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
507-
return new Ast\Type\ArrayShapeNode([]);
508-
}
509506

510-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
511-
$items = [$this->parseArrayShapeItem($tokens)];
507+
$items = [];
508+
$sealed = true;
512509

513-
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
514-
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
510+
do {
515511
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
512+
516513
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
517-
// trailing comma case
518514
return new Ast\Type\ArrayShapeNode($items);
519515
}
520516

517+
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) {
518+
$sealed = false;
519+
$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA);
520+
break;
521+
}
522+
521523
$items[] = $this->parseArrayShapeItem($tokens);
524+
522525
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
523-
}
526+
}while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
524527

525528
$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
526529
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
527530

528-
return new Ast\Type\ArrayShapeNode($items);
531+
return new Ast\Type\ArrayShapeNode($items, $sealed);
529532
}
530533

531534

‎tests/PHPStan/Parser/TypeParserTest.php‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,75 @@ public function provideParseData(): array
599599
),
600600
]),
601601
],
602+
[
603+
'array{a: int, b: int, ...}',
604+
new ArrayShapeNode([
605+
new ArrayShapeItemNode(
606+
new IdentifierTypeNode('a'),
607+
false,
608+
new IdentifierTypeNode('int')
609+
),
610+
new ArrayShapeItemNode(
611+
new IdentifierTypeNode('b'),
612+
false,
613+
new IdentifierTypeNode('int')
614+
),
615+
], false),
616+
],
617+
[
618+
'array{int, string, ...}',
619+
new ArrayShapeNode([
620+
new ArrayShapeItemNode(
621+
null,
622+
false,
623+
new IdentifierTypeNode('int')
624+
),
625+
new ArrayShapeItemNode(
626+
null,
627+
false,
628+
new IdentifierTypeNode('string')
629+
),
630+
], false),
631+
],
632+
[
633+
'array{...}',
634+
new ArrayShapeNode([], false),
635+
],
636+
[
637+
'array{
638+
* a: int,
639+
* ...
640+
*}',
641+
new ArrayShapeNode([
642+
new ArrayShapeItemNode(
643+
new IdentifierTypeNode('a'),
644+
false,
645+
new IdentifierTypeNode('int')
646+
),
647+
], false),
648+
],
649+
[
650+
'array{
651+
a: int,
652+
...,
653+
}',
654+
new ArrayShapeNode([
655+
new ArrayShapeItemNode(
656+
new IdentifierTypeNode('a'),
657+
false,
658+
new IdentifierTypeNode('int')
659+
),
660+
], false),
661+
],
662+
[
663+
'array{int, ..., string}',
664+
new ParserException(
665+
'string',
666+
Lexer::TOKEN_IDENTIFIER,
667+
16,
668+
Lexer::TOKEN_CLOSE_CURLY_BRACKET
669+
),
670+
],
602671
[
603672
'callable(): Foo',
604673
new CallableTypeNode(

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /