Skip to content

Commit cc94635

Browse files
committed
Merge branch '1.20.x' into 1.21.x
2 parents 97d18ea + 7d568c8 commit cc94635

File tree

2 files changed

+193
-27
lines changed

2 files changed

+193
-27
lines changed

Diff for: src/Parser/TypeParser.php

+106-27
Original file line numberDiff line numberDiff line change
@@ -522,47 +522,126 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
522522
$startLine = $tokens->currentTokenLine();
523523
$startIndex = $tokens->currentTokenIndex();
524524
if ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {
525-
$type = $this->parseNullable($tokens);
525+
return $this->parseNullable($tokens);
526526

527527
} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
528528
$type = $this->parse($tokens);
529529
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
530+
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
531+
$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
532+
}
530533

531-
} else {
532-
$type = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue());
533-
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
534-
535-
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
536-
$type = $this->parseGeneric(
537-
$tokens,
538-
$this->enrichWithAttributes(
539-
$tokens,
540-
$type,
541-
$startLine,
542-
$startIndex
543-
)
544-
);
545-
546-
} elseif (in_array($type->name, ['array', 'list'], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
547-
$type = $this->parseArrayShape($tokens, $this->enrichWithAttributes(
534+
return $type;
535+
} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
536+
$type = new Ast\Type\ThisTypeNode();
537+
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
538+
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
548539
$tokens,
549540
$type,
550541
$startLine,
551542
$startIndex
552-
), $type->name);
543+
));
544+
}
545+
546+
return $type;
547+
} else {
548+
$currentTokenValue = $tokens->currentTokenValue();
549+
$tokens->pushSavePoint(); // because of ConstFetchNode
550+
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {
551+
$type = new Ast\Type\IdentifierTypeNode($currentTokenValue);
552+
553+
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
554+
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
555+
$type = $this->parseGeneric(
556+
$tokens,
557+
$this->enrichWithAttributes(
558+
$tokens,
559+
$type,
560+
$startLine,
561+
$startIndex
562+
)
563+
);
564+
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
565+
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
566+
$tokens,
567+
$type,
568+
$startLine,
569+
$startIndex
570+
));
571+
}
572+
573+
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
574+
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
575+
$tokens,
576+
$type,
577+
$startLine,
578+
$startIndex
579+
));
580+
581+
} elseif (in_array($type->name, ['array', 'list', 'object'], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
582+
if ($type->name === 'object') {
583+
$type = $this->parseObjectShape($tokens);
584+
} else {
585+
$type = $this->parseArrayShape($tokens, $this->enrichWithAttributes(
586+
$tokens,
587+
$type,
588+
$startLine,
589+
$startIndex
590+
), $type->name);
591+
}
592+
593+
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
594+
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
595+
$tokens,
596+
$type,
597+
$startLine,
598+
$startIndex
599+
));
600+
}
601+
}
602+
603+
return $type;
604+
} else {
605+
$tokens->rollback(); // because of ConstFetchNode
606+
}
607+
} else {
608+
$tokens->dropSavePoint(); // because of ConstFetchNode
553609
}
554610
}
555611

556-
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
557-
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
558-
$tokens,
559-
$type,
560-
$startLine,
561-
$startIndex
562-
));
612+
$exception = new ParserException(
613+
$tokens->currentTokenValue(),
614+
$tokens->currentTokenType(),
615+
$tokens->currentTokenOffset(),
616+
Lexer::TOKEN_IDENTIFIER,
617+
null,
618+
$tokens->currentTokenLine()
619+
);
620+
621+
if ($this->constExprParser === null) {
622+
throw $exception;
563623
}
564624

565-
return $type;
625+
try {
626+
$constExpr = $this->constExprParser->parse($tokens, true);
627+
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
628+
throw $exception;
629+
}
630+
631+
$type = new Ast\Type\ConstTypeNode($constExpr);
632+
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
633+
$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
634+
$tokens,
635+
$type,
636+
$startLine,
637+
$startIndex
638+
));
639+
}
640+
641+
return $type;
642+
} catch (LogicException $e) {
643+
throw $exception;
644+
}
566645
}
567646

568647

Diff for: tests/PHPStan/Parser/TypeParserTest.php

+87
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,22 @@ public function provideParseData(): array
770770
)
771771
),
772772
],
773+
[
774+
'callable(): Foo<Bar>[]',
775+
new CallableTypeNode(
776+
new IdentifierTypeNode('callable'),
777+
[],
778+
new ArrayTypeNode(new GenericTypeNode(
779+
new IdentifierTypeNode('Foo'),
780+
[
781+
new IdentifierTypeNode('Bar'),
782+
],
783+
[
784+
GenericTypeNode::VARIANCE_INVARIANT,
785+
]
786+
))
787+
),
788+
],
773789
[
774790
'callable(): Foo|Bar',
775791
new UnionTypeNode([
@@ -1956,6 +1972,77 @@ public function provideParseData(): array
19561972
'callable(): ?int',
19571973
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new NullableTypeNode(new IdentifierTypeNode('int'))),
19581974
],
1975+
[
1976+
'callable(): object{foo: int}',
1977+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new ObjectShapeNode([
1978+
new ObjectShapeItemNode(new IdentifierTypeNode('foo'), false, new IdentifierTypeNode('int')),
1979+
])),
1980+
],
1981+
[
1982+
'callable(): object{foo: int}[]',
1983+
new CallableTypeNode(
1984+
new IdentifierTypeNode('callable'),
1985+
[],
1986+
new ArrayTypeNode(
1987+
new ObjectShapeNode([
1988+
new ObjectShapeItemNode(new IdentifierTypeNode('foo'), false, new IdentifierTypeNode('int')),
1989+
])
1990+
)
1991+
),
1992+
],
1993+
[
1994+
'callable(): $this',
1995+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new ThisTypeNode()),
1996+
],
1997+
[
1998+
'callable(): $this[]',
1999+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new ArrayTypeNode(new ThisTypeNode())),
2000+
],
2001+
[
2002+
'2.5|3',
2003+
new UnionTypeNode([
2004+
new ConstTypeNode(new ConstExprFloatNode('2.5')),
2005+
new ConstTypeNode(new ConstExprIntegerNode('3')),
2006+
]),
2007+
],
2008+
[
2009+
'callable(): 3.5',
2010+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new ConstTypeNode(new ConstExprFloatNode('3.5'))),
2011+
],
2012+
[
2013+
'callable(): 3.5[]',
2014+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new ArrayTypeNode(
2015+
new ConstTypeNode(new ConstExprFloatNode('3.5'))
2016+
)),
2017+
],
2018+
[
2019+
'callable(): Foo',
2020+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new IdentifierTypeNode('Foo')),
2021+
],
2022+
[
2023+
'callable(): (Foo)[]',
2024+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new ArrayTypeNode(new IdentifierTypeNode('Foo'))),
2025+
],
2026+
[
2027+
'callable(): Foo::BAR',
2028+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new ConstTypeNode(new ConstFetchNode('Foo', 'BAR'))),
2029+
],
2030+
[
2031+
'callable(): Foo::*',
2032+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new ConstTypeNode(new ConstFetchNode('Foo', '*'))),
2033+
],
2034+
[
2035+
'?Foo[]',
2036+
new NullableTypeNode(new ArrayTypeNode(new IdentifierTypeNode('Foo'))),
2037+
],
2038+
[
2039+
'callable(): ?Foo',
2040+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new NullableTypeNode(new IdentifierTypeNode('Foo'))),
2041+
],
2042+
[
2043+
'callable(): ?Foo[]',
2044+
new CallableTypeNode(new IdentifierTypeNode('callable'), [], new NullableTypeNode(new ArrayTypeNode(new IdentifierTypeNode('Foo')))),
2045+
],
19592046
];
19602047
}
19612048

0 commit comments

Comments
 (0)